本文已参与「新人创作礼」活动,一起开启掘金创作之路。
给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
示例 1:
输入: dividend = 10, divisor = 3 输出: 3 解释: 10/3 = truncate(3.33333..) = truncate(3) = 3 示例 2:
输入: dividend = 7, divisor = -3 输出: -2 解释: 7/-3 = truncate(-2.33333..) = -2
提示:
被除数和除数均为 32 位有符号整数。 除数不为 0。 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。本题中,如果除法结果溢出,则返回 2^31 − 1。
思路:
本来看到这道每日一题真的高兴(因为昨天才刚学了位运算的加减乘除今天就用上了)没想到啊没想到,我一开始按照昨天的思路使用位运算来解决,结果测试用例给了我多个暴击!恶心心!一直变着法子的溢出。后来想到把被除数和除数都变成负数进行计算,然后溢出的问题倒是解决了,倒是直接不会了。。因为用的是从第31位开始往下找,但是被除数左移的时候疯狂报错,哎。后来不用换了种想法才终于好了。
这道题首先恶心就恶心在会用INT_MIN,INT_MAX来造成溢出,因为int型是-2147483648到2147483647的,把符号直接去掉变成正的时候就溢出了。所以在一开始的时候就要进行判断,把特殊条件给直接返回了。
因为存在符号的问题,所以进行符号判断,再最后要根据符号重新把全是负数的给换回来,我这里采用的是异或来进行符号判断,当然也可以使用其他的。
因为除法本质就是减法,所以为了效率更高的进行运算,所以要减去最大的数这样循环次数比较小。以2的幂次方开始往上找,直到找到最大的小于被除数的数为止(当然在找的时候也不要忘了把cnt也同时*2,因为这个相当于多少次减去除数。)最后直到被除数不够减了,结束循环输出答案。
代码区:
class Solution {
public:
int divide(int dividend, int divisor) {
if (dividend == INT_MIN && divisor == -1)//进行特殊情况判断,当被除数是int型最小的数并且除数为-1.这时结果会是INT_MAX+1,溢出了。所以直接return
return INT_MAX;
if (divisor == 1)//当除数为1,不管怎么样都等于被除数
return dividend;
bool flag = ((dividend ^ divisor) >= 0) ? true : false;//通过异或来进行判断符号
if (dividend > 0) dividend = -dividend;//为了避免溢出,把所有的数都转化成负数进行计算
if (divisor > 0) divisor = -divisor;
int res = 0;
while(1) {
int a = dividend, b = divisor, cnt = 1;
if (a > b) break;//当被除数无法减去除数时结束,因为是负数,所以是大于号
while(a - b <= b) {//通过while来找出最小的大于被除数的2的幂
cnt <<= 1;//等效于cnt+=cnt;也就是乘2,从尽可能大的开始减这样效率高
b += b;//这里本来也想和上一行一样的,但是不知道为什么就是报错,所以还是老老实实的加吧
}
res += cnt;//次数累加
dividend -= b;//被除数减去此时的b来进行下一次循环
}
return flag ? res : -res;//最后进行符号的调整
}
};
新手上路,有错请指正;