两数相除

题目

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。

示例 1:
输入: dividend = 10, divisor = 3
输出: 3

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

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

来源:力扣(LeetCode)
https://leetcode-cn.com/problems/divide-two-integers

解题思路

首先,分析题目的难点在于环境只能存储32为有符号整数,所以边界问题应该是输入:-2^31,-1,这样我们在处理的时候就会超过int数据类型的取值范围。所以得用指令来判断是否超过int取值范围,我们使用下面的语句:

unsigned int p1 = dividend==INT_MIN?INT_MIN:abs(dividend);
unsigned int p2 = divisor==INT_MIN?INT_MIN:abs(divisor);

使用 (表达式1)?(表达式2):(表达式3)来判断,如果输入的除数和被除数等于INT_MIN,则变量就为INT_MIN,否则就取绝对值(因为取绝对值函数abs()返回的值不能超过int所能表示的大小)

然后另外一个需要解决的是符号问题,我们使用异或指令来判断:

bool emp = (dividend ^ divisor) < 0;  //使用异或来判断除数和被除数是否异号

emp就为结果的符号位

一开始我的思路是使用减法,被除数循环减掉除数,知道被除数小于除数,则减法的次数就为商,但这种方法出现的问题是:当遇到被除数远大于除数时,效率很低

所以就使用移位
首先我们得知道,数据左移一位相当于乘2,数据右移一位相当于除2,除法的运算就是(被除数-余数)/除数=商,那我们换个思路,除数=(被除数-余数)/商,那么问题就转换为:什么时候被除数/商最接近除数,那么此时就能求出商,具体代码如下:

class Solution {
public:
    int divide(int dividend, int divisor) {
		if (divisor == 1)
			return dividend;
		if (dividend == INT_MIN && divisor == -1)
			return INT_MAX;
		//首先要判断除数和被除数是否超过32位有符号数
		unsigned int p1 = dividend==INT_MIN?INT_MIN:abs(dividend);
		unsigned int p2 = divisor==INT_MIN?INT_MIN:abs(divisor);
		if (p1 < p2)
			return 0;
		bool emp = (dividend ^ divisor) < 0;  //使用异或来判断除数和被除数是否异号
		unsigned int result = 0;
		for (int i = 31; i >= 0; i--) {
			if ((p1 >> i) >= p2) {//找出足够大的数2^n*divisor
				result += ((unsigned int)1) << i;//将结果加上2^n
				p1 -= p2 << i;//将被除数减去2^n*divisor
			}
		}
		return emp ? -(int)result : (int)result;//符号相异取反
    }
};

要注意的是:当被除数除于2的某次方时最接近除数,此时2^n次方有可能不是我们最后要求的结果,因为此时的余数还有可能能整除除数,所以需要将被减数减去此时的2 ^n,然后继续判断

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值