Divide Two Integers不使用乘除法來計算兩個數相除
題目描述
分析
不使用乘除法來計算兩個數相除,那就從除法的定義出發:商表示的是被除數裡包含了多少個除數。那最直接的一種辦法,就是迴圈減除數,累加次數,直到不能再減。這麼粗暴的辦法,很容易會超時,舉個極端的例子,若被除數是INT_MAX即2147483647,除數是1,那麼就得減2147483647次,程式才能執行結束。所以,我們應該每次減多一點,我第一想到的便是位操作。因為,位操作可以看成是特殊的乘除法,如向左移一位,便是翻倍(即乘2);向右移一位,便是減半(即除2)。舉個簡單的例子來對照看,3的二進位制是11,6的二進位制是110,12的二進位制是1100,…
所以,
核心思想:
被除數
=除數商*
=除數(2^0 * q0 + 2^1 q1 + 2^2 *q2 + 2^3*q3 + ….. + 2^n*qn)
其中,q0~qn的取值要麼為1,要麼為0.舉例1,
75
=5*15
=5*(2^0 *1 + 2^1 *1 + 2^2 *1 + 2^3*1)舉例2,
15
=3*5
=3*(2^0 *1 + 2^1 *0 + 2^2 *1)程式碼的編寫思路如下,
1、確定n值。
每次翻倍的累加除數(1,2,4,8,16,…倍),看直到多少倍(n),除數會大於被除數,同時記下除數被累加的次數和當前的移位數(即倍數)。
2、確定q0~q(n-1)的值,確認是0還是1,同時更新累加次數
3、根據除數和被除數的符號,確定商的符號程式碼實現
int divide(int dividend, int divisor) {
//溢位判定
if(divisor==0 || (dividend==INT_MIN && divisor==-1))
return INT_MAX;
//符號確定
bool sign=0;
if((dividend>0&&divisor>0)||(dividend<0&&divisor<0)){
sign=1;
}
long ldividend=labs(dividend);
long div=labs(divisor);
long count=1;
int bits=0; //bits為移的位數
//確定指數級翻倍的最大翻倍數(多項式的次數)
while(div<=ldividend){
count=count<<1;
div=div<<1;
bits++;
}
div=div>>1;
bits--;
count=count>>1;
//確定多項式形式的其他位的值(是1還是0)
int i;
long copyd;
for(i=bits-1;i>=0;i--){
copyd=labs(divisor);
div=div+(copyd<<i); //<<的優先順序小於+,要加括號
//除數可以再加上copyd<<i,也即可以再累加上1<<i次
if(div<=ldividend){
count=count+(1<<i);
}
//不能加,嘗試失敗,除數的值還原到剛才未加時候的值
else{
copyd=labs(divisor);
div=div-(copyd<<i);
}
}
if(sign)
return count;
else
return -count;
}
遺留現象
1、上述程式碼是在以C++的形式下通過的,若以C的形式是過不了的。2、另外一個奇怪的現象是,上述程式碼在eclipse上執行,有些測試集的結果會和leetcode執行的不一樣。
圖1:leetcode程式設計環境下的測試截圖
圖2:eclipse C++的測試截圖圖1和圖2使用的是相同的程式碼,見上文。然而測試結果不一樣。在eclipse中debug會發現,即使是使用labs或者fabs先強制轉換型別後來取絕對值(long temp=(long)dividend; long ldividend=labs(temp);),並使用long或double型來儲存,-2147483648的絕對值依然是-2147483648,這也就是造成結果不對的原因。那為什麼在leetcode的程式設計環境下執行就不會出現這種問題呢?我暫時還不清楚,知道的親歡迎留言告訴我。
後續
在文章的開頭,我說到直接單純的一次一次的累加,可能會超時。那如果減少一半的累加次數,還會超時嗎?於是我便寫了下面的程式碼,與上文程式碼不同的地方是在確定指數級翻倍的最大翻倍數之後,採取的是簡單的逐次迴圈累加統計次數。下面的程式碼提交,就有時候會Accept,有時候會提示Time limit Exceeded。所以,最好還是用上文程式碼的方法,一定不會超時。
class Solution
{
public:
int divide(int dividend, int divisor) {
if(divisor==0 || (dividend==INT_MIN && divisor==-1))
return INT_MAX;
bool sign=0;
if((dividend>0&&divisor>0)||(dividend<0&&divisor<0)){
sign=1;
}
long ldividend=labs(dividend);
long div=labs(divisor);
long count=1;
int bits=0; //bits為移的位數
if(div>ldividend)
return 0;
while(div<=ldividend){
count=count<<1;
div=div<<1;
bits++;
}
div=div>>1;
bits--;
count=count>>1;
long copyd=labs(divisor);;
while(div<=ldividend){
div=div+copyd;
count++;
}
if(div!=ldividend)
count--;
if(sign)
return count;
else
return -count;
}
};
相關文章
- [LeetCode] Divide Two Integers 兩數相除LeetCodeIDE
- 【leetcode】29. Divide Two Integers 不能使用乘除法的整數除法LeetCodeIDE
- Divide Two IntegersIDE
- Leetcode Divide Two IntegersLeetCodeIDE
- Leetcode 29 Divide Two IntegersLeetCodeIDE
- Leetcode-Divide Two IntegersLeetCodeIDE
- Divide Two Integers leetcode javaIDELeetCodeJava
- leetcode-29. Divide Two IntegersLeetCodeIDE
- [LeetCode] 29. Divide Two IntegersLeetCodeIDE
- leetcode29_Divide Two IntegersLeetCodeIDE
- LeetCode T29 Divide Two IntegersLeetCodeIDE
- 輾轉相除法原理
- 演算法練習--LeetCode--29. Divide Two Integers: 100%演算法LeetCodeIDE
- 輾轉相除法的原理
- 計算機計算小數除法的陷阱計算機
- 透徹理解輾轉相除法
- 輾轉相除法 氣泡排序排序
- 輾轉相除法原理解析
- 【演算法分析與設計】輾轉相除法演算法
- python用輾轉相除法求最大公約數Python
- 輾轉相除法求最大公約數——[js練習]JS
- A - Yet Another Two Integers Problem ACMACM
- C++中的輾轉相除法C++
- 【C語言】聊聊輾轉相除法C語言
- LeetCode 29——兩數相除LeetCode
- FCC - 253 計算一個整數的階乘
- python LeetCode 兩數相除PythonLeetCode
- Java 兩個整數相除保留兩位小數,將小數轉化為百分數Java
- JavaScript計算兩個日期相差天數JavaScript
- java計算兩個日期相差年數Java
- LeetCode Problem-Sum of Two IntegersLeetCode
- js計算兩個日期相差的天數(不包含小時分鐘秒)JS
- JavaScript 計算兩個時間相差天數JavaScript
- javascript計算兩個日期相差的天數JavaScript
- Calendar:計算兩個日期相差的天數
- js計算兩個日期相差的正月數JS
- JAVA-LeetCode中等29兩數相除JavaLeetCode
- leetcode 371. Sum of Two IntegersLeetCode