LeetCode 029 Divide Two Integers

题目要求返回两个int的整除结果,但是不能使用乘号、除号、取模运算符。

不能用除法,那我们用减法。将被除数不断减去除数,直到不能再减,减法的次数就是商。但是用脚趾头想都知道这样不行,因为如果除数为1的话要减到猴年马月?

既然是算除法,那试商肯定是需要用到乘法,但是不能用乘号。想一想int类型还可以怎么执行乘法?对了,就是左移运算符。左移一次相当于乘以2。那我们就可以仿造笔算竖式除法,从高位到低位试商,不过把十进制换成二进制。当被除数和除数都是正数时,就可以用下述的算法。

            int k = divisor, j = 0, r = dividend, d = 0; //r为余数,d为商
            while(k > 0 && dividend >= k) k <<= 1, j++;
            k = divisor;
            for(int i = j - 1 ; i >= 0 ; i--) {
                if(r >= (k << i) ) { 
                    r -= k << i;
                    d += 1 << i;
                }
            }

当然,题目中的int即可以为正,又可以为负,我们能不能取绝对值都变成正数处理呢?不行!因为负的int比正的int多出一个数,|INT_MAX| != |INT_MIN|。当除数为INT_MIN时,商要么是0,要么是1,可以在函数开头就处理掉。当被除数为INT_MIN时,就没法特殊处理,也需要有试商的过程。所以我就把除数取和被除数相同的符号,然后对正数和负数都写一个试商的过程。

接着考虑结果溢出的问题。显然当除数为0的时候结果溢出。然后一想整除应该不会越除越大,所以就不会溢出了吗?错!当被除数为INT_MIN,除数为-1的时候,商为INT_MAX+1,也溢出了。除数非0的溢出就这一种情况。所以在函数开头特殊处理即可。

所以最后的代码是:

int divide(int dividend, int divisor) {

        int sign;
        if(dividend == 0)
            return 0;
        if(divisor == 0)
            return INT_MAX;
        if(divisor == dividend)
            return 1;

        if(divisor == INT_MIN)
            return 0;

        if(dividend == INT_MIN && divisor == -1)
            return INT_MAX;

        if((dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0))
            sign = 1;
        else 
            sign = -1, divisor = -divisor;

        if(dividend > 0) {
            if(divisor > dividend)
                return 0;

            int k = divisor, j = 0, r = dividend, d = 0;
            while(k > 0 && dividend >= k) k <<= 1, j++;
            k = divisor;
            for(int i = j - 1 ; i >= 0 ; i--) {
                if(r >= (k << i) ) {
                    r -= k << i;
                    d += 1 << i;
                }
            }
            return d * sign;
        }
        else {
            if(divisor < dividend)
                return 0;

            int k = divisor, j = 0, r = dividend, d = 0;
            while(k < 0 && dividend <= k) k <<=1, j++;
            k = divisor;
            for(int i = j - 1 ; i >= 0 ; i--) {
                if(r <= (k << i)) {
                    r -= k << i;
                    d += 1 << i;
                }
            }

            return d * sign;
        }
}

总结:此类题目一定要牢记|INT_MAX| != |INT_MIN|

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值