1. 题目来源
链接:29. 两数相除
2. 题目解析
基于朴素思想求商的话,可以一直让 x-y
,当 x< y
时减法停止,相减的次数就是商。显然,这个可以描述为数学形式为 x-ky<x
,k
即为商。当 k
非常大时,一步步减的时间复杂度就直接爆炸了。
基于 倍增 / 快速幂 / 二进制思想,可将 k
表示成二进制形式,最多相减的次数就变为 logk
次了。预处理 2^0*y,2^1*y,...,2^30*y
。从 k
的二进制最高位开始递减判断,若 x>=2^30*y
则说明 x
的第 30 位一定是 1,就可以将其减去,x-=2^30y
,同时需要给商加上一个 2^30
。负数情况变为正数做即可
- 时间复杂度: O ( l o g ( n ) ) O(log(n)) O(log(n))。两字符串长度之和。
- 空间复杂度: O ( l o g ( n ) ) O(log(n)) O(log(n))
代码:
class Solution {
public:
int divide(int x, int y) {
typedef long long LL;
vector<LL> exp;
bool flag = false; // 判断符号
if (x < 0 && y > 0 || x > 0 && y < 0) flag = true;
LL a = abs((LL)x), b = abs((LL)y); // 防止是int最小值后abs后溢出
for (LL i = b; i <= a; i = i + i) exp.push_back(i); // 预处理2进制项
LL res = 0;
for (int i = exp.size() - 1; i >= 0; --i) {
if (a >= exp[i]) {
a -= exp[i];
// 在此最多可能移位为31位,即负数最大值,32位全为1的情况,可能导致int溢出,强转为long long 类型
res += 1LL << i;
}
}
if (flag) res = -res;
if (res > INT_MAX || res < INT_MIN) res = INT_MAX;
return res;
}
};