LeetCode/solutions/29. Divide Two Integers.md

2.5 KiB
Raw Blame History

29. Divide Two Integers

思路

不使用取模、除法等操作求两数相除的商。
常规思路就是不断循环用被除数减去除数然后记录被减的次数即商,但是亲测会超时。
既然每次减去除数会超时那么一次性地减去除数的2倍、4倍、8倍......(之所以取2的次方倍是为了移位操作即可快速实现)呢,基于这个思路,我们有以下算法: 假设除数和被除数都是正数例如考虑15除3先用15-3发现结果等于12>3再尝试用15-6发现结果得9>3再尝试用15-12发现结果3=3再尝试用15减去24发现不够减 则应该用15-12然后余3此时商得4然后再考虑3除3依然用上面的思路得到商为1最终的结果就是将每一步得到的商相加即可。
如果是负数的话先取绝对值最后判断符号即可。
另外需要考虑两个溢出的情况:

  • dividend == INT_MIN && divisor == -1,结果是-INT_MIN超出了int的表示范围。
  • ·dividend == INT_MIN && divisor == 1,结果是INT_MIN`虽然没有超过范围但是我们是按照绝对值计算结果的所以计算过程res也会溢出。

另外需要注意的是再用abs(x)求绝对值的时候一定要先将x转换成long long型这样abs(x)返回的才是long long型保证不溢出。否则若x=INT_MIN的话求绝对值就超过 int型表示范围了。

参考

C++

class Solution {
public:
    int divide(int dividend, int divisor) {
        if(dividend == 0) return 0;
        if(dividend == INT_MIN && divisor == -1) return INT_MAX;
        if(dividend == INT_MIN && divisor == 1) return INT_MIN;
        int res = 0;
        long long dvd = abs((long long)dividend); // 一定要先将dividend和divisor转换成long long型这样abs才返回long long型
        long long dvs = abs((long long)divisor);
        long long dvs_bk = dvs; // 除数备份
        
        while(dvd >= dvs){
            int curr = 1;
            dvs <<= 1;
            while(dvd - dvs >= 0){
                curr *= 2;
                dvs <<= 1;
            } // dvd < dvs
            dvs >>= 1;
            dvd -= dvs;
            dvs = dvs_bk;
            res += curr;
        }
        if(dividend > 0 && divisor < 0) res *= -1;
        else if(dividend < 0 && divisor > 0) res *= -1;
        return res;
    }
};