力扣第二十九题-两数相除

569 阅读2分钟

这是我参与更文挑战的第26天,活动详情查看: 更文挑战

前言

力扣第二十九题 两数相除 如下所示:

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

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

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

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

一、思路

如果不用乘法怎么知道除法的结果呢?其实也很简单就是 累加。举个例子,要知道 9 / 4 等结果,就一直将4相加, 4 + 4 = 8 < 94 + 4 + 4 = 12 > 9,故 9/4 = 2

但是这样一直累加会有一个问题,就是次数会很多。比如要计算 100 / 2 要一直累加 50 次才能得到正确的结果。为了合理的减少累加的次数,这里可以使用 倍增法,就是下一次相加的结果乘以二。如果和比被除数大,则变小一点。

举个例子

此处以 100/2 作为例子,具体的步骤如下所示:

ret表示返回结果,ret = 0

  1. 第一步:2 < 100,ret = 1
  2. 第二步:2 + 4 < 100, ret = 1 + 2 = 3
  3. 第三步:(2 + 4) + 8 < 100, ret = 3 + 4 = 7
  4. 第四步:(2 + 4 + 8) + 16 < 100,ret = 7 + 8 = 15
  5. 第五步:(2 + 4 + 8 + 16) + 32 < 100,ret = 15 + 16 = 31
  6. 第六步:(2 + 4 + 8 + 16 + 32) + 64 > 100,ret = 31。此时出现了大于的情况,下一次累加的数要缩小到加上后不会出现大于的情况
  7. 第七步:此时会一直试着寻找合适的累加数,直到寻找到累加数 32 为合适的值 (2 + 4 + 8 + 16 + 32) + 32 < 100,ret = 31 + 16 = 47
  8. 第八步:再次加上 32 会发生大于的情况,所以会再次寻找合适的累加数 4 ,即 (2 + 4 + 8 + 16 + 32 + 32) + 4 < 100,ret = 47 + 2 = 49
  9. 第九步:再次加上 4 会发生大于的情况,所以会再次寻找合适的累加数 2,(2 + 4 + 8 + 16 + 32 + 32 + 4) + 2 = 100,ret = 49 + 1 = 50
  10. 最后,返回结果 ret = 50

在实际实现的过程中因为会将比较的值转为 long 类型,便于处理。

二、实现

实现代码

为了方便处理,我们先判断出最终结果的正负值。然后再将被除数和除数转为正数,便于后续处理。

/**
     * 倍增法
     */
    public int divide(int dividend, int divisor) {
        // 特殊情况
        if(dividend == 0) return 0;
        if(divisor == 1) return dividend;
        if(divisor == -1){
            if(dividend> Integer.MIN_VALUE) return -dividend;
            return Integer.MAX_VALUE;
        }

        // 结果
        int ret = 0;
        // 转为long
        long d = dividend;
        long r = divisor;
        // 判断正负号
        boolean flag = true;
        if (d > 0 && r < 0 || d < 0 && r > 0) {
            flag = false;
        }
        // 保证是两个正数
        d = d < 0 ? -d : d;
        r = r < 0 ? -r : r;
        // 开始倍增
        long temp = 0;
        long add = r;  // 累加值
        int multiple = 1;   // 倍数
        while (temp < d || add > r) {
            if (temp == d) {
                break;
            }
            // 选择合适的累加数
            while (temp + add > d) {
                add = add >> 1;
                multiple = multiple >> 1;
            }
            ret += multiple;
            temp += add;
            add += add;
            multiple += multiple;
        }
        // 返回结果
        return flag ? ret : -ret;
    }

测试代码

    public static void main(String[] args) {
        int ret = new Number29().divide(100 , 2);
        System.out.println(ret);
    }

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥