[LeetCode 29.] 兩數相除
阿新 • • 發佈:2021-09-22
LeetCode 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
。
解題思路
不讓用除法和取餘,那就只能用減法來模擬除法了。
顯然,暴力減法是有問題的,對於 INT32_MAX / 1
這種場景會超時。這裡我們必然要想辦法加倍減。
既然題目告訴我們不能用乘法操作,那我們就用位移操作來代替乘法。也就是對 dd / dr = k
按照 k 進行二進位制分解運算,也就是說 dd = dr * k = sum(dri * 2^i)
,按照這種方式逆運算出 k 每一位上的數字即可。
思路如下:
- 首先將除數和被除數對齊,也就是找到一個數,這個數字是被除數的2的冪次倍,且恰好比被除數小;
- 然後從這個數開始,每一輪迴圈減去此數,直到被除數比此數小,此時結果需要累加的就是減法次數乘上此數相對於除數的倍數;
- 之後此數右移一位,也就是降為原來的1/2,重複上一步,直到數字比原本的除數要小,結束演算法。
參考程式碼
class Solution { public: int divide(int dividend, int divisor) { assert(divisor != 0); int flag = 1; if (dividend > 0 && divisor < 0 || dividend < 0 && divisor > 0) flag = -1; int64_t dd = llabs(dividend); int64_t dr = llabs(divisor); if (dd < dr) return 0; if (dd == dr) return flag; int64_t dri = dr; int64_t base = 1; while (dd >= dri) { dri <<= 1; base <<= 1; } dri >>= 1; base >>= 1; int64_t res = 0; while (dd >= dr && dri >= dr) { while (dd >= dri) { dd -= dri; res += base; } dri >>= 1; base >>= 1; } res *= flag; if (res < INT32_MIN || res > INT32_MAX) return INT32_MAX; return res; } // AC };