LeetCode-029-两数相除

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

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/divide-two-integers

解题思路

  1. 被除数为0直接返回0
  2. 除数为1直接返回被除数
  3. 除数为-1时, 如果被除数是整型最小值, 则返回整型最大值(整型最小值取相反数会溢出), 否则返回被除数的相反数
  4. 其余结果
    1. 记录结果正负, 也就是看被除数和除数的正负情况, 同号为正, 反之为负
    2. 将被除数和除数取绝对值, 在递归方法中计算, 返回绝对值的计算结果
    3. 根据上面记录的正负结果, 返回最后结果

    递归方法
    举例:10 / 3, 比较10和3的大小, 10比3大, 则商必定大于1, 然后将3翻倍为6, 比较10和6, 还是10大, 则商必定大于2, 再将6翻倍为12, 现在是10小, 所以最终结果必定在2到4之间, 不妨将10 - 6 = 4, 比较4于3, 4大, 则结果至少为2 + 1 = 3, 将3翻倍为6, 4小于6, 于是重复类似的操作, 4 - 3 = 1, 1小于3, 直接返回2 + 1 + 0 = 3 为最终结果, 看代码会清晰得多

  • 优化: 由于采用绝对值计算需要用 long 接收变量(因为整型最小值取相反数会溢出), 索性将两个数置为负数, 用负数计算就可以避免采用 long 类型接收参数, 减少开销, 不过需要注意负数的除数在"翻倍"的过程中要判断是否为负数, 因为翻倍可能使它溢出变为整数
int a = Integer.MIN_VALUE;
System.out.println(a - 1); // 整型最小值 - 1 = 整型最大值

代码

class Solution {
    int divide(int dividend, int divisor) {
        // 被除数为0直接返回0
        if (dividend == 0) {
            return 0;
        }
        if (divisor == 1) {
            return dividend;
        }
        if (divisor == -1) {
            return dividend == Integer.MIN_VALUE ? Integer.MAX_VALUE : -dividend;
        }
        // 记录结果正负的符号
        int sign = 1;
        if (dividend > 0 && divisor < 0 || dividend < 0 && divisor > 0) {
            sign = -1;
        }
        // 原先采用绝对值来计算, 但是整数最小值取相反数会溢出
        // 所以将数统统置为负数, 直接用两个负数计算
        dividend = dividend > 0 ? -dividend : dividend;
        divisor = divisor > 0 ? -divisor : divisor;
        int result = div(dividend, divisor);
        return sign == 1 ? result : -result;
    }

    private int div(int dividend, int divisor) {
        // 如果被除数比除数大, 直接返回0
        // 注意这里都是负数, 所以比较的是绝对值
        if (dividend > divisor) {
            return 0;
        }
        // 被除数比除数小(绝对值大), 则被除数至少有1个除数(数值比较)
        // count记录被除数的数值等于几个除数
        int count = 1;
        // 既然count至少为1, 那就尝试让除数翻倍, 看看count能否达到2
        int curDivisor = divisor;
        while (dividend < curDivisor + curDivisor && curDivisor + curDivisor < 0) {
            count += count; // 结果翻倍
            curDivisor += curDivisor; // 被除数翻倍
        }
        // 还需要检查dividend减去curDivisor后是否还能包括几个divisor
        return count + div(dividend - curDivisor, divisor);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值