[leetcode] 29. 两数相除

题目描述

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

整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8-2.7335 将被截断至 -2

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

注意:假设我们的环境只能存储 32 位 有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果商 严格大于 231 − 1 ,则返回 231 − 1 ;如果商 严格小于 -231 ,则返回 -231

示例 1:

输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = 3.33333.. ,向零截断后得到 3 。

示例 2:

输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = -2.33333.. ,向零截断后得到 -2 。

提示:

  • -231 <= dividend, divisor <= 231 - 1
  • divisor != 0

解题方法

倍增

按照 a a a b b b 都是正数的情况说明。我们设 x × b < = a x \times b<=a x×b<=a 2 × x × b > a 2 \times x \times b>a 2×x×b>a,如果求 k × b = a k \times b = a k×b=a,那么 k k k 一定满足 x < = k < 2 x x <= k < 2x x<=k<2x

按照 d i v i d e n d dividend dividend d i v i s o r divisor divisor 都是正数的情况说明。我们可以利用上面的方式不断对 d i v i s o r divisor divisor 倍增,同时记录倍增数 m u l mul mul m u l mul mul 即为 k k k,初始为1),当 d i v i d e n d − m u l × d i v i s o r < m u l × d i v i s o r dividend− mul \times divisor < mul \times divisor dividendmul×divisor<mul×divisor时, d i v i d e n d = d i v i d e n d − m u l × d i v i s o r dividend = dividend− mul \times divisor dividend=dividendmul×divisor,答案追加 m u l mul mul。然后重复利用上面的方式计算倍增数 m u l mul mul d i v i d e n d dividend dividend 不断缩小,答案追加 m u l mul mul。直到 d i v i d e n d < d i v i s o r dividend < divisor dividend<divisor 时,即求出最终结果。

由于负数的表示范围更大,可以将 d i v i d e n d dividend dividend d i v i s o r divisor divisor 转化为负数,再利用倍增的思想计算结果。具体代码如下。

java代码

public int divide(int dividend, int divisor) {
    if (dividend == Integer.MIN_VALUE && divisor == -1) {
        return Integer.MAX_VALUE;
    }
    // 记录结果正负
    boolean flag = (dividend < 0) ^ (divisor < 0);
    // 将a和b设置为负数,a和b符号相同时方便辗转相减(如果设置为正数,dividend或divisor有一方是Integer.MIN_VALUE时,a或b转化为正数会越界)
    int a = (dividend < 0) ? dividend : -dividend;
    int b = (divisor < 0) ? divisor : -divisor;
    //记录结果
    int result = 0;
    // a > b时,a / b = 0
    while (a <= b) {
        // 记录倍增倍数
        int mul = 1;
        // 用temp临时记录b
        int temp = b;
        // 当temp + temp >= a时,mul倍增,temp倍增(之所以用减法是因为temp相加可能会超过整形范围)
        while (a - temp <= temp) {
            mul += mul;
            temp += temp;
        }
        // a减去倍增后的temp,剩余的a再与b相除
        a -= temp;
        result += mul;
    }
    return flag ? -result : result;
}

复杂度分析

时间复杂度: O ( l o g 2 N ) O(log^2N) O(log2N),其中 N N N 表示 32 位整数的范围。最坏情况系下倍增的次数为 O ( l o g N ) O(logN) O(logN) + O ( l o g N 2 ) O(log\frac {N} {2}) O(log2N) + O ( l o g N 4 ) O(log\frac {N} {4}) O(log4N) + …… + O ( l o g N N ) O(log\frac {N} {N}) O(logNN),故渐进复杂度为 O ( l o g 2 N ) O(log^2N) O(log2N)
空间复杂度: O ( 1 ) O(1) O(1)


  • 个人公众号
    个人公众号
  • 个人小游戏
    个人小游戏
  • 28
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的大鱼人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值