LeetCode刷题之两数相除

481 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

题目描述

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

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

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

  • 被除数和除数均为 32 位有符号整数
  • 除数不为 0
  • 假设我们的环境只能存储 32 位有符号整数,其数值范围是[−2^31, 2^31 − 1]。本题中,如果除法结果溢出,则返回2^31 − 1

示例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

解法:快速幂 + 二分

分析:为了避免超时,在每次减去除数的时候,尽可能减去除数的倍数,由于这里不能使用乘法,可以使用移位运算代替,每次向左移一位表示乘以2。这样每次减去 2^n ,可以加速找到解。

class Solution {
    public int divide(int low, int up) {
        boolean is_neg = false;
        if(low < 0 && up > 0 || low > 0 && up < 0) is_neg = true;

        long a = Math.abs((long)low), b = Math.abs((long)up);
        // 将分子对应的比特位存下来, 不需要存31位,只需将小于分母的所有比特位保存下来就行
        List<Long> exp = new ArrayList();
        for(long i = b; i <= a; i = i << 1){
            exp.add(i);
        }

        long k = 0;
        //逆序遍历分子比特位, 如果被减数-减数那么说明商的这一位是1, 对应比特位由1<<i位得到
        for(int i = exp.size() - 1; i >= 0; i--){
            if(a >= exp.get(i)) {
                a -= exp.get(i);
                k += (long)1 << i; 
            }
        }
        if(is_neg) k *= -1;
        if(k > Integer.MAX_VALUE || k < Integer.MIN_VALUE) return Integer.MAX_VALUE;
        return (int)k;
    }
}