1. 程式人生 > >LeetCode 29 - 兩數相除 - [位運算]

LeetCode 29 - 兩數相除 - [位運算]

題目連結:https://leetcode-cn.com/problems/divide-two-integers/description/

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

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

示例 1:

輸入: dividend = $10$, divisor = $3$
輸出: $3$

示例 2:

輸入: dividend = $7$, divisor = $-3$
輸出: $-2$

說明:

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

 

題解:

首先, 知道除數不為零,那麼溢位唯一的可能就是 $-2^{31} \div (-1) = 2^{31}$,把這個情況特判掉。再特判掉被除數為零的情況。

那麼剩下來,被除數和除數都不為零,可以統一先變成兩個正數相除。

由於不允許使用乘除模,首先最簡單的,就是考慮累減,不過這題卡掉了累減的做法,考慮類似於快速冪那樣的思路。

任何被除數 $a$,對於除數 $b$,均可以表示為  $a = (2^{k_1} + 2^{k_2} + \cdots + 2^{k_n})b + r$,其中 $r = a \bmod b$。相應的 $a / b = 2^{k_1} + 2^{k_2} + \cdots + 2^{k_n}$。

只要用左移和右移代替乘 $2$ 和除 $2$,然後找出 $k_1 \sim k_n$ 即可。

 

AC程式碼:

static const auto io_sync_off = []()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();
struct Solution
{
    inline long long _abs(long long x){return x<0?-x:x;}
    int divide(int dividend, int
divisor) { if(dividend==-2147483648 && divisor==-1) return 2147483647; if(dividend==0) return 0; long long f=1, a=dividend, b=divisor; if((a<0 && b>0) || (a>0 && b<0)) f=-1; a=_abs(a), b=_abs(b); long long res=0, t=1; while(a>b) b<<=1, t<<=1; while(a>=_abs(divisor)) { while(a<b) b>>=1, t>>=1; a-=b, res+=t; } return f==-1?-res:res; } };