leetcode 29.两数相除

leetcode 29.两数相除

题目描述

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

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

示例 1:

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

示例 2:

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

说明:

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

解题思路

两数两除,不能使用乘法、除法和mod运算符,那么一个很简单的思路就出来了,就是不断的用被除数不断的减去除数,直到被除数小于除数的时候,结束迭代,但是如果这样做的话,势必会超时,举个例子 dividend=INT_MIN, divisor=1,如果这样迭代的话,就要花费很长的时间。
在计算机里,位运算的执行效率是非常高的,一个数字左移一位相当于除以2,右移一位相当于乘以2,那么就可以采用这样的方法来减少迭代次数。意思是,每一次相减都让除数的值翻倍,当然累加次数也要翻倍,直到dividend小于divisor的时候停止。举几个简单的例子

例子一: dividend = 10, divisor = 1

  • 采用保留求解,就是10不停的减去1,那么需要循环十次。

  • 采用位移的方法 ,是怎么操作的呢,看下面的表格,

    1. 首先建立一个临时的变量temp=divisor,让dividend去减temp,count记一,这时候发现dividend大于等于temp,那么dividor翻倍,count也翻倍,然后发现dividend仍然大于等于temp,temp继续翻倍,那么count也应该在原来的基础上翻倍(记录被减了多少次);
    2. 再继续判断temp继续翻倍的话,dividend就小于temp了,这时候dividend=2,让此时的dividend去和divisor比较,发现dividend大于等于divisor,那么就继续把temp=divisor,循环上面的操作

    上面写的步骤只是为了好理解,其实就是 dividend = 8 + 2 + 余数 = 23*1 + 21*1 + 余数

    dividendtempcount
    10 >= 211
    10 >= 422
    10 >= 844
    10 < 16,此时10减去8,并与divisor比较88 此时res+8
    2 >= 211
    2 < 4 此时 2减去2,并与divisor比较22 此时res+2
    合计 res10

例子二:dividend = 123, divisor = 3;

123 = 25*3 + 23*3 + 3

dividendtempcount
123 >= 631
123 >= 1262
123 >= 24124
123 >= 48248
123 >= 964816
123 < 192 此时 123减去96,并与divisor比较9632 此时res+32
27 >= 631
27 >= 1262
27 >= 24124
27 <= 48 此时27减去24,并与divisor比较248 此时res+8
3 < 6 此时 3减去3,并与divisor比较31 此时res+1
合计 res41

通过上面的例子就可以知道,通过位移的方法可以大大加上迭代的次数,提高运算效率,具体代码如下

class Solution {
public:
    int divide(int dividend, int divisor) {
        if(divisor == 0 || dividend == 0){      // 被除数为零或者除数为零直接返回零
            return 0;
        }
        if(divisor == 1){     // 如果除数是1,就不需要额外的操作,直接返回被除数本身
            return dividend;
        }
        // 当被除数为INT_MIN, 除数是-1时需要特别注意,会出现溢出的情况,因为int范围是-2147483648~2147483647,相除的结果就是2147483648,当然是溢出;所以这里做一个特殊处理
        if(divisor == -1 && dividend == INT_MIN){  
            return INT_MAX;
        }
        bool sign = (dividend > 0)^(divisor > 0);  // 通过异或, 判断是不是异号
        long a = dividend, b = divisor;         // 这里把两个数转成long类型,并取绝对值,取绝对值是为了好运算,如果是不采用绝对值,就要分四种情况(--,++,+-,-+)来讨论反而更复杂
        a = abs(a);
        b = abs(b);
        int res = 0;
        while(a >= b){  // 如果a<b,那么循环终止
            int count = 1;
            long temp = b;
            while(a >= (temp<<1)){  // 不断的采用位移操作,尽可能减去最大的除数的倍数
                temp = temp << 1;
                count = count << 1;
            }
            a -= temp;
            res += count;
        } 
        // 通过sign判断是否异号,并在结果res上添加对应符号
        return sign ? -res : res;
    }
};

欢迎大家关注我的个人公众号,同样的也是和该博客账号一样,专注分享技术问题,我们一起学习进步
在这里插入图片描述

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值