29. Divide Two Integers (M)

Divide Two Integers (M)

Given two integers dividend and divisor, divide two integers without using multiplication, division and mod operator.

Return the quotient after dividing dividend by divisor.

The integer division should truncate toward zero.

Example 1:

Input: dividend = 10, divisor = 3
Output: 3

Example 2:

Input: dividend = 7, divisor = -3
Output: -2

Note:

  • Both dividend and divisor will be 32-bit signed integers.
  • The divisor will never be 0.
  • Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [231,2311]. For the purpose of this problem, assume that your function returns 2 31 − 1 2^{31} − 1 2311 when the division result overflows.

题意

在不使用乘法、除法、取模操作的前提下,实现除法。若得到的商溢出Integer的范围,则返回Integer的最大值。

思路

首先要明确正负数除法的规则,经过实验可得Java的规则是使得到的商尽可能接近0(即直接省去得到的负数商的小数部分),说明商与除数的乘积的绝对值小于等于被除数的绝对值,在这个基础上实现除法的算法。

最直接的做法是让被除数挨个减去(若正负数除法则为加上)除数,复杂度为 O ( N ) O(N) O(N)但在商的绝对值很大的情况下会超时。

更高效方法的大致方向是:将除数和被除数都化为绝对值后,倍增除数,找到比被除数小的那个值,记录倍增的次数n, 2 n 2^n 2n即是所求的商,复杂度为 O ( l o g N ) O(logN) O(logN)。(当然具体实现更加复杂)

因为题目要求环境只能存储int范围的值,所以不使用long,也不使用与乘除相似的位运算,具体操作直接看代码。


代码实现

class Solution {
    public int divide(int dividend, int divisor) {
        // 只有这一种情况会造成商溢出,先处理掉
        if (dividend == Integer.MIN_VALUE && divisor == -1) {
            return Integer.MAX_VALUE;
        }

        // 记录商的正负值
        boolean isMinus = ((dividend < 0) != (divisor < 0));
        
        // 如果除数或被除数中有一个是Integer.MIN_VALUE,那么取绝对值就会溢出
        // 所以全部转化为负数进行处理
        dividend = dividend > 0 ? -dividend : dividend;
        divisor = divisor > 0 ? -divisor : divisor;
		
        // 如果被除数已经比除数大(因为全是负数),商只可能为0
        if (dividend > divisor) {
            return 0;
        }

        int quotient = 1;		// 商的绝对值
        int d = divisor;		// 当前需要在除数上累加的值
        int sum = divisor;		// 累加后的除数
        int count = 1;			// 当前累加值对应的divisor个数,d = count * divisor

        while (true) {
            // 当累加后的除数绝对值仍小于等于被除数时,则进行累加
            // sum + d < 0 的判断是为了防止sum+d后溢出
            if (sum + d < 0 && sum + d >= dividend) {
                sum += d;				// 将待加值累加到除数上
                d += d;					// 待加值自我累加
                quotient += count;		// 更新商
                count += count;			
            } else {
                // 当且仅当加上待加值后的除数绝对值大于被除数,且待加值正好为最原始除数时才跳出
                // 因为这时累加后的除数已经达到小于等于被除数的最大值,多加一个除数都不行
                if (d == divisor) {
                    break;		
                } else {
                    // 重置待加值,以尽可能使累加除数的绝对值接近被除数
                    d = divisor;
                    count = 1;
                }
            }
        }
		
        // 最后注意商的正负号
        return isMinus ? -quotient : quotient;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值