两数相除,不用除法-java

最初的想法:

//a不停减去b,减到a小于b,计算减了多少次,就是结果
    public int divide(int a,int b){
        int sign=1;
        //如果a或b有一个是负数,那么就定义最后的结果为负数
        if((a>0&&b<0)||(a<0&&b>0)){
            sign = -1;
        }
        //Math.abs(-2147483648)=-2147483648
        a = Math.abs(a);
        b = Math.abs(b);
        int res = 0;
        while(a>=b){
            a-=b;
            res++;
        }
        return sign*res;
    }

考虑边界问题

    public int divide(int a,int b){
        //环境只支持32位整数
        // 32 位最大值:2^31 - 1 = 2147483647
        // 32 位最小值:-2^31 = -2147483648
        // -2147483648 / (-1) = 2147483648 > 2147483647 越界了
        if(a==Integer.MIN_VALUE && b==-1)
            return Integer.MAX_VALUE;
        //如果a或b有一个是负数,那么就定义最后的结果为负数
        //用异或^来判断a和b符号是否相同,都为正数或都为负数异或的结果就是false,一个为正一个为负就是true
        int sign = (a>0)^(b>0)?-1:1;
        if(a>0) a = -a;
        if(b>0) b = -b;
        int res = 0;
        while(a<=b){
            a -= b;
            res ++;
        }
        return sign*res;
    }

优化,考虑减去除数的倍数

// 时间复杂度:O(logn * logn),n 是最大值 2147483647 --> 10^10
public int divide(int a, int b) {
    if (a == Integer.MIN_VALUE && b == -1)
        return Integer.MAX_VALUE;
    int sign = (a > 0) ^ (b > 0) ? -1 : 1;
    if (a > 0) a = -a;
    if (b > 0) b = -b;
    int res = 0;
    while (a <= b) {
        int value = b;
        int k = 1;
        // 0xc0000000 是十进制 -2^30 的十六进制的表示
        // 判断 value >= 0xc0000000 的原因:保证 value + value 不会溢出
        // 可以这样判断的原因是:0xc0000000 是最小值 -2^31 的一半,
        // 而 a 的值不可能比 -2^31 还要小,所以 value 不可能比 0xc0000000 小
        // -2^31 / 2 = -2^30
        while (value >= 0xc0000000 && a <= value + value) {
            value += value;
            // 代码优化:如果 k 已经大于最大值的一半的话,那么直接返回最小值
            // 因为这个时候 k += k 的话肯定会大于等于 2147483648 ,这个超过了题目给的范围
            if (k > Integer.MAX_VALUE / 2) {
                return Integer.MIN_VALUE;
            }
            k += k;
        }
        a -= value;
        res += k;
    }
    // bug 修复:因为不能使用乘号,所以将乘号换成三目运算符
    return sign == 1 ? res : -res;
}
// 时间复杂度:O(1)
public int divide(int a, int b) {
    if (a == Integer.MIN_VALUE && b == -1)
        return Integer.MAX_VALUE;
    int sign = (a > 0) ^ (b > 0) ? -1 : 1;
    a = Math.abs(a);
    b = Math.abs(b);
    int res = 0;
    for (int i = 31; i >= 0; i--) {
        // 首先,右移的话,再怎么着也不会越界
        // 其次,无符号右移的目的是:将 -2147483648 看成 2147483648
        // 注意,这里不能是 (a >>> i) >= b 而应该是 (a >>> i) - b >= 0
        // 这个也是为了避免 b = -2147483648,如果 b = -2147483648
        // 那么 (a >>> i) >= b 永远为 true,但是 (a >>> i) - b >= 0 为 false
        if ((a >>> i) - b >= 0) { // a >= (b << i)
            a -= (b << i);
            // 代码优化:这里控制 res 大于等于 INT_MAX
            if (res > Integer.MAX_VALUE - (1 << i)) {
                return Integer.MIN_VALUE;
            }
            res += (1 << i);
        }
    }
    // bug 修复:因为不能使用乘号,所以将乘号换成三目运算符
    return sign == 1 ? res : -res;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值