29. 两数相除 - LeetCode

29. 两数相除

题目链接

二分+倍增

  • 不使用除法算除法,很自然就想到二分答案

    • 但是需要注意,要找到比商小,但是离商最接近的整数,所以二分的时候,需要l=mid,循环条件为l<r
  • 但是也不能使用乘法,所以需要用倍增,原理如下

    • 假设a与b相乘,即为a个b相加
    • 我们将a用二进制表示,a & (1 << x)为1,即代表有2^x个b相加
    • 将式子转换为(a >> x) & 1和(b << x),那么就只需在迭代时右移a和左移b即可
class Solution {
    public int divide(int dividend, int divisor) {
        if(dividend == 0)
            return 0;
        if(dividend == Integer.MIN_VALUE && divisor == -1)
            return Integer.MAX_VALUE;
        int signal = (dividend ^ divisor) < 0 ? -1 : 1;
        long a = Math.abs((long)dividend);
        long b = Math.abs((long)divisor);
        long l = 0, r = a;
        while(l < r){
            long mid = (l + r + 1) >> 1;
            long c = mul(mid, b);
            if(c < a) l = mid;
            else if(c > a) r = mid - 1;
            else return signal * (int) mid;
        }
        return signal * (int) l;
    }
    private long mul(long a, long b){
        long ans = 0;
        while(a > 0){
            if((a & 1) == 1)
                ans += b;
            a >>= 1;
            b <<= 1;
        }
        return ans;
    }
}
  • 二分的时间复杂度是O(logn),倍增乘法的时间复杂度也是O(logn),所以最终的时间复杂度是O(log2n)

二进制枚举

  • 要避免乘除法,核心思想一定是用位运算来代替乘2和除2,但是用倍增来代替乘法,显然是过于复杂了,为何不直接用位运算来计算商呢?
  • 眼界放开,就直接枚举商的二进制的每一位,这样枚举的结果都是2的幂,乘法可以用(b << i)来表示,省去了倍增这一步骤,枚举二进制的时间复杂度也和二分查找相同
  • 本质上来说,就是贪心,先用大数去乘,再用小数去乘,所得结果相加即为最终答案

class Solution {
    public int divide(int dividend, int divisor) {
        if(dividend == 0)
            return 0;
        if(dividend == Integer.MIN_VALUE && divisor == -1)
            return Integer.MAX_VALUE;
        int signal = (dividend ^ divisor) < 0 ? -1 : 1;
        int ans = 0;
        long a = Math.abs((long)dividend);
        long b = Math.abs((long)divisor);
        for(int i = 32; i >=0; i--)
            if((a >> i) >= b){
                ans += (1 << i);
                a -= (b << i);
            }
        return signal * ans;
    }
}
上一篇:Medium | LeetCode 166. 分数到小数 | 数学


下一篇:如何查找Linux中所有777权限的文件?