LeetCode 29 Divide Two Integers

LeetCode 29 Divide Two Integers

题目大意:给你俩32位的数,不能用除法、乘法和模运算,让求出它们的商

分析:

题目意思挺容易理解的,难一点的地方就是不能用这些运算,所以就需要去考虑除法的本质。
我们知道,四则运算中乘法运算是加法的演化,或者说本质上可以通过加法来理解,那么对于除法,也应该就对应和减法有一定的相关性。这也是我首先想到的思路:
对被除数不断的减去除数,同时对减去的次数计数,每减去一次自然加1,最后当被除数不够减的时候,计数的值就是商,比如
样例中的10除以3,减去3次之后,10变成1,小于3不够减,就结束。答案也就是3。用递归或者非递归(循环)都能很快的写出来,但是比较慢,因为如果给一个特殊的case就不太好使,比如这个题几个最蛋疼的点,被除数是INT_MAX,除数是1,这相当于从1加到INT_MAX。
所以在这个思想基础上,可以进行优化。我们完全没有必要按照每次只加一个除数的速度来考虑,借鉴二分的思想,我们可以每次把这个需要减去的数扩大一倍,而扩大一倍恰好又可以利用位运算来实现。还是刚才那个例子10除以3,可以这样来考虑,10比3大,3就扩大一倍变成6,然后10还是大于6,所以继续扩大一倍变成12,但是12超出了10,所以就结束了。这样一来就能加快被除数缩减的速度。
那现在的问题就是如何得到商,还是刚才的例子,10比3大,意味着至少是有一倍,所以不妨记一个值n为1,然后3扩大一倍变成6之后,10还是比6大,所以10至少又是6的一倍,自然就至少是3的2倍。可能这个例子还不够明显,如果换成17除以3,那现在6继续扩大一倍,变成12,17还是比12大,所以17至少是12的一倍,也就至少是6的两倍,3的四倍,这就很明显能看出来这个值n也是在同步增大两倍,弄清楚了这一点,接下来的过程就很简单了。回到刚才的例子,当6再扩大两倍就变成了12,10比12小,所以6变成12这一步就不能左移了,而是10减去6,得到4,这就意味着对于6这一部分算完了,能得到2的部分商,剩下的4继续作为运算(其实就是10 = 2 * 3 + 4),接下来的过程类似刚才的过程,4比3大,但是比6小,所以不需要左移,得到新的部分商1,然后接着4减去3,得到1,1此时小于3,连一倍都不够,也就是所谓的余数,所以可以跳出循环,到这里算法就结束了。

代码实现

class Solution {
using ll = long long;
public:
    int divide(int dividend, int divisor) {
        int flag = ( (ll)dividend < 0) ^ ((ll)divisor < 0) == 0 ? 1 : -1;
        ll ans = 0;
        ll temp, dvd = abs((ll)dividend), dvs = abs((ll)divisor);
        int cnt;
        while (dvd >= dvs){
            temp = dvs;
            cnt = 1;
            while (temp << 1 <= dvd){
                temp <<= 1;
                cnt <<= 1;
            }
            dvd -= temp;
            ans += cnt;
        }
        if (flag == -1) return flag * ans;
        return abs(flag * ans) > INT_MAX ? INT_MAX : flag * ans;
    }
};

代码细节

  • 因为带有符号,所以先把它们的符号做一个判断,用flag保存,同号为1,异号为-1
  • 需要考虑溢出的问题,也是这个题最操蛋的地方,有几个例子用到了-2147483648除以-1,或者是-2147483648除以1 ,算出来的值应该是2147483648和-2147483648。但2147483648这个值超出了32位可以表示的范围,我们在算法中为了防止溢出,是使用long long的大类型来保存ans,所以ans的值是可以保存2147483648,但这不是32位能表示的数,而应该是2147483647(INT_MAX),但是对于-2147483648,是32位可以表示的,所以应该返回-2147483648,这是需要考虑的一个细节,所以我的代码中分了两种情况返回。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值