1. 程式人生 > >[LeetCode]problem 29. Divide Two Integers

[LeetCode]problem 29. Divide Two Integers

TAG

位操作二分查詢?除法就是被除數包含多少個除數

題目連結

方法

沒有思路,直接看得DISCUSS,寫得太好了。

首先,dividend是被除數,divisor是除數;

接著,除法表示被除數中有多少個除數,所以在不讓使用乘法、模運算的情況下,我們使用位操作來以2倍的速度增大除數,直到再增大就要大於被除數了。那麼此時我們能夠直到除數增大了多少倍,那麼就是其中包含多少個除數。其個數就是除法的結果。當然,此時還沒有除盡,所以用當前被除數減去該增大的除數,並開始下次迴圈,直到被除數小於除數為止。

由於除數二倍形式增大,並通過減法、再重新增大來不斷逼近最後的結果,其過程有些類似二分查詢。

最後,溢位情況:

  1. 除數為0

  2. 被除數為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,故可能溢位。