[LeetCode]problem 29. Divide Two Integers
阿新 • • 發佈:2019-02-14
TAG
位操作; 二分查詢?; 除法就是被除數包含多少個除數
方法
沒有思路,直接看得DISCUSS,寫得太好了。
首先,dividend是被除數,divisor是除數;
接著,除法表示被除數中有多少個除數,所以在不讓使用乘法、模運算的情況下,我們使用位操作來以2倍的速度增大除數,直到再增大就要大於被除數了。那麼此時我們能夠直到除數增大了多少倍,那麼就是其中包含多少個除數。其個數就是除法的結果。當然,此時還沒有除盡,所以用當前被除數減去該增大的除數,並開始下次迴圈,直到被除數小於除數為止。
由於除數二倍形式增大,並通過減法、再重新增大來不斷逼近最後的結果,其過程有些類似二分查詢。
最後,溢位情況:
除數為0
被除數為INT_MIN , 而除數為-1, 其結果為
INT_MAX + 1
, 超過了int的範圍,故溢位。
程式碼
class Solution {
public:
int divide(int dividend, int divisor) {
if( divisor == 0
|| ( dividend == numeric_limits<int>::lowest() && divisor == -1 )
)
{
return numeric_limits<int>::max();
}
bool isPositive = ( dividend > 0 ) == ( divisor > 0) ;
unsigned dividendU = abs(static_cast<long long>(dividend));
unsigned divisorU = abs(static_cast<long long>(divisor)); // just in case INT_MIN , and `unsigned` can store it safely
int result = 0 ;
while(dividendU >= divisorU)
{
int nrBitMoved = 0 ;
unsigned movedDivisor = divisorU;
while(dividendU >= movedDivisor && ! isOverflowAfterMove(movedDivisor))
{
movedDivisor <<= 1;
++nrBitMoved;
}
if(dividendU >= movedDivisor)
{
// movedDivisor will overflow
dividendU -= movedDivisor;
result += ( 1 << nrBitMoved );
}
else
{
// movedDivisor is bigger
movedDivisor >>= 1;
--nrBitMoved;
dividendU -= movedDivisor;
result += ( 1 << nrBitMoved );
}
}
return isPositive ? result : -result;
}
private :
bool isOverflowAfterMove(unsigned num)
{
// if the highest bit is 1 , then after left move , it will overflow
return ( (num >> (sizeof(num) * 8 - 1)) == 1 ) ;
}
};
後記
首先,abs在C++11下有3個過載,分別對int, long , long long . 此外,還有labs
, llabs
.
然後,程式碼中我檢測了增大的除數是否有可能溢位。加上後面的if判斷,這可能導致了我的程式碼效率不高。這對於我的程式碼是必須的!因為如果一貫增大除數的確有可能溢位。但是,上面列出的DISCUSS中的程式碼沒有使用溢位檢測,其也是對的。因為,他使用的是long long ! 由於被除數的絕對值範圍是在unsigned int 之中的,故在long long、且剛好能大於被除數的情況下,其不可能溢位。但是我的程式碼中使用的是unsigned,故可能溢位。