1. 程式人生 > 實用技巧 >29. 兩數相除

29. 兩數相除

題目:

  給定兩個整數,被除數dividend和除數divisor。將兩數相除,要求不使用乘法、除法和 mod 運算子。

  返回被除數dividend除以除數divisor得到的商。

  整數除法的結果應當截去(truncate)其小數部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

示例1:

輸入: dividend = 10, divisor = 3
輸出: 3
解釋: 10/3 = truncate(3.33333..) = truncate(3) = 3


示例2:

輸入: dividend = 7, divisor = -3
輸出: -2
解釋: 7/-3 = truncate(-2.33333..) = -2

提示:

  被除數和除數均為 32 位有符號整數。
  除數不為0。
  假設我們的環境只能儲存 32 位有符號整數,其數值範圍是 [−2^31, 2^31− 1]。本題中,如果除法結果溢位,則返回 2^31− 1。

解答:

  看了標籤為二分法,沒有思路,直接看解答:

  題目分類提示了二分查詢,那麼按二分查詢的思路去想就行了,既然要求不能使用乘除模運算,那麼就讓除數不斷自加倍增,與被除數對比,倍增過頭了就初始化為原始的除數值再次迴圈倍增,迴圈過程中被除數減去除數不斷減小,直到小於除數為止,其過程就是把二分查詢中的 mid = (left + right) / 2 替換成了divisor * 2,把 left 和 right 替換成了 divisor_tmp 和 divideng_tmp,這樣理解就比較直觀了。

//傳進div的值必須是正整數,但是INT_MIN取絕對值會產生溢位問題,所以必須對它採取一定的措施,
//即先讓它減一次除數或者加一次除數(主要取決於除數的正負號),然後作為被除數的INT_MIN就不會產生溢位問題了。
int divSub(int dividend, int divisor)
{
    if (divisor>dividend) return 0;
    int res = 1;
    int original_divisor = divisor;

    while (dividend - divisor >= divisor)//特別需要注意的地方是dividend-divisor之後還大於等於divisor,即是dividend>=2divisor
{ divisor += divisor; res += res;//記錄被除數是除數的多少倍 } res += divSub(dividend - divisor, original_divisor); return res; } int divide(int dividend, int divisor) { int res = 0; int flag = ((dividend>0 && divisor>0) || (dividend<0 && divisor<0)); //先處理特殊值,即是處理邊界溢位問題 INT_MIN if (divisor == 1) return dividend; if (divisor == INT_MIN) return dividend == INT_MIN ? 1 : 0; if (divisor == -1) return dividend == INT_MIN ? INT_MAX : -dividend; if (dividend == INT_MIN)//如果被除數是32位最小整數必須進行一定的處理,先讓其減或者加一次除數 { dividend = (flag) ? (dividend - divisor) : (dividend + divisor); res++; } dividend = (dividend>0) ? dividend : -dividend; divisor = (divisor>0) ? divisor : -divisor; res += divSub(dividend, divisor); return (flag) ? res : -res; }

  根據上面的思路,自己寫了程式碼,並測試通過:

int divideSub(int dividend, int divisor)
{
    if (divisor > dividend)
        return 0;

    int res = 1;
    int originalDiv = divisor;
    while (dividend - divisor >= divisor)
    {
        divisor += divisor;
        res += res;
    }

    res += divideSub(dividend-divisor, originalDiv);

    return res;
}

int divide2(int dividend, int divisor) 
{
    if (dividend == 0)
        return 0;

    //處理特殊情況
    if (divisor == 1)
        return dividend;
    else if (divisor == -1)
    {
        if (dividend == INT_MIN)
        {
            return INT_MAX;
        }
        return -dividend;
    }
    else if (divisor == INT_MIN)
    {
        if (dividend == INT_MIN)
            return 1;
        //INT_MIN的值較大,如果被除數是其他值,不夠除,則直接返回0
        return 0;
    }

    //兩個引數是否同符號
    bool sameSymbol = (dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0);
    int res = 0;
    if (dividend == INT_MIN)    //下面遞迴時,傳入的都是正數,INT_MIN傳入會溢位,先減或者加上一個除數
    {
        if (sameSymbol)
            dividend -= divisor;
        else
            dividend += divisor;
        res++;
    }

    if (dividend < 0)
        dividend = -dividend;
    if (divisor < 0)
        divisor = -divisor;

    res += divideSub(dividend, divisor);
    if (sameSymbol)
        return res;
    return -res;
}