leetcode29 兩數相除(hard,位運算)

題目

給定兩個整數,被除數 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]。本題中,如果除法結果溢出,則返回 231 − 1。

思路

無法使用乘法,只能使用位運算來做

/**
     * 解題思路:這題是除法,所以先普及下除法術語
     * 商,公式是:(被除數-餘數)÷除數=商,記作:被除數÷除數=商...餘數,是一種數學術語。
     * 在一個除法算式裏,被除數、餘數、除數和商的關係爲:(被除數-餘數)÷除數=商,記作:被除數÷除數=商...餘數,
     * 進而推導得出:商×除數+餘數=被除數。
     *
     * 要求商,我們首先想到的是減法,能被減多少次,那麼商就爲多少,但是明顯減法的效率太低
     *
     * 那麼我們可以用位移法,因爲計算機在做位移時效率特別高,向左移1相當於乘以2,向右位移1相當於除以2
     *
     * 我們可以把一個dividend(被除數)先除以2^n,n最初爲31,不斷減小n去試探,當某個n滿足dividend/2^n>=divisor時,
     *
     * 表示我們找到了一個足夠大的數,這個數*divisor是不大於dividend的,所以我們就可以減去2^n個divisor,以此類推
     *
     * 我們可以以100/3爲例
     *
     * 2^n是1,2,4,8...2^31這種數,當n爲31時,這個數特別大,100/2^n是一個很小的數,肯定是小於3的,所以循環下來,
     *
     * 當n=5時,100/32=3, 剛好是大於等於3的,這時我們將100-32*3=4,也就是減去了32個3,接下來我們再處理4,同樣手法可以再減去一個3
     *
     * 所以一共是減去了33個3,所以商就是33
     *
     * 這其中得處理一些特殊的數,比如divisor是不能爲0的,Integer.MIN_VALUE和Integer.MAX_VALUE
     *
     */
class Solution {
public:
    int divide(int dividend, int divisor) {
        if(divisor == 0) return 0;
        if(divisor == 1) return dividend;
        // int溢出的判斷
        if(dividend == INT_MIN && divisor == -1) return INT_MAX;
        // 兩個數取異或,判斷符號是否相同
        bool neg = false;
        int res = 0;
        if((dividend^divisor) < 0) neg = true;

        long a = abs((long)dividend);
        long b = abs((long)divisor);
        if(a < b) return res;
        
        // 我們可以把一個dividend(被除數)先除以2^n,n最初爲31,不斷減小n去試探
        // 當某個n滿足dividend/2^n>=divisor時,表示我們找到了一個足夠大的數
        // 這個數*divisor是不大於dividend的,所以我們就可以減去2^n個divisor,以此類推
        for(int i = 31;i >= 0;i--){
            if((a>>i) >= b){
                res += 1<<i;
                a -= b<<i;
            }
        }
        return neg? -1*res:res;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章