leetcode 29. 两数相除(Java版)

43 篇文章 0 订阅
28 篇文章 0 订阅

题目名,两数相除,表面看起来人畜无害。结果…,他喵的提交十几次才过。

题目描述(题目难度,中等)

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

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

示例 1:

输入: dividend = 10, divisor = 3
输出: 3

示例 2:

输入: dividend = 7, divisor = -3
输出: -2

说明:

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

题目求解

解法一

最开始看题目也没什么时间复杂度的要求,以为题目难点主要在于不能使用乘除和取余运算。于是想到一个直白的试减法就提交了,试减法的思路就是每次循环都将被除数减去一个除数,这样最终被除数被减去的次数就是商。
其实这个解法在英文版官网上是可以提交通过的,这样也比较符合划定的中等难度的级别。但到了中文版,就会说超出时间限制,无法通过。所以没办法,只能优化了这个解法,最终在中文版网站提交通过。
这个试减法,我是将输入的被除数和除数统一转换为负数,再进行试减的。为什么这样呢,我们平常不是习惯于正数的计算吗。其实我最开始也是统一转化为正数来做的,但这样做有一个问题就是,如果被除数为 Integer.MIN_VALUE,则它无法转化为对应的正数。需要注意:Integer.MIN_VALUE == -Integer.MIN_VALUE

class Solution {
    public int divide(int dividend, int divisor) {
    	if(dividend == Integer.MIN_VALUE && divisor == -1) return Integer.MAX_VALUE; // 题意
    	if(divisor == Integer.MIN_VALUE){ // **此处如不特判,后面会陷入死循环
    		if(dividend == Integer.MIN_VALUE) return 1;
    		else return 0;
    	}
    	if(divisor == -1) return -dividend;
    	if(divisor == 1) return dividend;
        boolean d = true; // 同号标志
        if(dividend <= 0 && divisor > 0){
        	d = false;
        	divisor = -divisor;
        }else if(dividend >= 0 && divisor < 0){
        	d = false;
        	dividend = -dividend;
        }else if(dividend >= 0 && divisor > 0){
        	dividend = -dividend;
        	divisor = -divisor;
        }
        int result = 0;
        while(true){
        	dividend -= divisor;
        	if(dividend > 0) return d == true ? result : -result;
        	++result;
        }
    }
}
解法二

加速的试减法,使用移位运算来加速试减。

class Solution {
    public int divide(int dividend, int divisor) {
    	if(dividend == Integer.MIN_VALUE && divisor == -1) return Integer.MAX_VALUE; // 题意
    	if(divisor == Integer.MIN_VALUE){ // **此处如不特判,后面会陷入死循环
    		if(dividend == Integer.MIN_VALUE) return 1;
    		else return 0;
    	}
    	if(divisor == -1) return -dividend;
    	if(divisor == 1) return dividend;
        boolean d = true; // 同号标志
        if(dividend <= 0 && divisor > 0){
        	d = false;
        	divisor = -divisor;
        }else if(dividend >= 0 && divisor < 0){
        	d = false;
        	dividend = -dividend;
        }else if(dividend >= 0 && divisor > 0){
        	dividend = -dividend;
        	divisor = -divisor;
        }
        int div = divisor, k = 1, result = 0;
        final int bound = Integer.MIN_VALUE >> 1;
        while(true){
        	dividend -= div;
        	if(dividend > 0){
        		if(k == 1) return d == true ? result : -result;
        		else{
        			dividend += div;
        			div = divisor;
        			k = 1;
        			continue;
        		}
        	}
        	result += k;
        	if(div >= bound){ // ****溢出判断,不能让 div 左移后溢出了        		
        		div <<= 1;
        		k <<= 1;
        	}
        }
    }
}

如果感觉迷糊,看个运算实例就懂了,
假设被除数 dividend = 20,除数 divisor = 3。
加速试减法的流程如下:

  1. dividend = 20 - 3 = 17,divisor = 3,k = 1,result = 1(result 为最终要返回的结果)
  2. dividend = 17 - 3*2 = 11,divisor = 6,k = 2,result = 3(将 k 累加进 result)
  3. dividend = 11 - 6*2 = -1,dividend < 0,则 divisor = 3,k = 1
  4. dividend = 11 - 3 = 8,divisor = 3,k = 1,result = 4
  5. dividend = 8 - 3*2 = 2,divisor = 6,k = 2,result = 6
  6. dividend = 2 - 6*2 = -10,dividend < 0,则 divisor = 3,k = 1
  7. dividend = 2 - 3 = -1,dividend < 0,又 k == 1,算法结束,result = 6

所以 20 除 3 的商就为 6。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值