LeetCode/solutions/29. Divide Two Integers.md
2020-06-17 20:38:49 +08:00

61 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [29. Divide Two Integers](https://leetcode.com/problems/divide-two-integers/)
# 思路
不使用取模、除法等操作求两数相除的商。
常规思路就是不断循环用被除数减去除数然后记录被减的次数即商,但是亲测会超时。
既然每次减去除数会超时那么一次性地减去除数的2倍、4倍、8倍......(之所以取2的次方倍是为了移位操作即可快速实现)呢,基于这个思路,我们有以下算法:
假设除数和被除数都是正数例如考虑15除3先用15-3发现结果等于12>3再尝试用15-6发现结果得9>3再尝试用15-12发现结果3=3再尝试用15减去24发现不够减
则应该用15-12然后余3此时商得4然后再考虑3除3依然用上面的思路得到商为1最终的结果就是将每一步得到的商相加即可。
如果是负数的话先取绝对值最后判断符号即可。
需要考虑唯一溢出的情况:
* `dividend == INT_MIN && divisor == -1`,结果是`-INT_MIN`超出了int的表示范围。
还需要考虑一些特殊情况:
* `dividend == 0`直接返回0即可
* `divisor == 1`,直接返回`dividend`因为我们是按照绝对值计算res的所以这样可以避免当`dividend=INT_MAX`中间结果溢出。
另外需要注意的是再用abs(x)求绝对值的时候要考虑x是否是INT_MIN。
1. 对于`divisor == INT_MIN`可以直接得到res为1或0直接返回即可
2. 而对于`dividend`,我们可以求`abs(dividend) - 1`来避免溢出最后加上这个1即可。
> 也可以先将x转换成long long型这样abs(x)返回的是long long型保证不溢出。
[参考](https://leetcode.com/problems/divide-two-integers/discuss/13407/Detailed-Explained-8ms-C%2B%2B-solution)
# C++
``` C++
class Solution {
public:
int divide(int dividend, int divisor) {
if(dividend == 0) return 0;
if(dividend == INT_MIN && divisor == -1) return INT_MAX; // 唯一可能的溢出情况
if(divisor == 1) return dividend;
if(divisor == INT_MIN) return dividend == INT_MIN ? 1 : 0;
int abs_dividend_minus_1 = abs(dividend + (dividend < 0 ? 1: -1));
int abs_divisor = abs(divisor), step = abs(divisor), step_i= 1;
int res = 0;
while(abs_dividend_minus_1 >= abs_divisor){
while(abs_dividend_minus_1 < step){
step >>= 1;
step_i >>= 1;
}
abs_dividend_minus_1 -= step;
res += step_i;
if(step <= (INT_MAX >> 1)){
step <<= 1;
step_i <<= 1;
}
}
if(abs_dividend_minus_1 + 1 == abs_divisor) res += 1;
if((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0)) return -res;
return res;
}
};
```