题意
在不使用%*/的情况下, 求int x / int y
思路
算法1
假设 x/y=z 。最先想的是二分一下z的多少,但是我们考虑到在judge的时候,不能使用乘法,于是这个想法基本可以排除。
我们想一下在小学的时候算除法的过程:即用被除数一直去减除数直到不够减。那么我们能否考虑:假设我们这次减1个,下次减2个,下次减4个呢,即我们将每次减的数翻倍。其实就是一个二进制分解的过程。
现在,假设我们要计算 37/4=9 。我们这样想,即 37=4⋅9+1 。我们将9进行二进制表示为1001。即 37=4⋅(23+20)+1 。
其实就是用 37−4⋅23 ,再减去 4∗20 。即每次找到够减的那个4的 2k 倍。
显然,我们不能从最低的 20 开始减,于是,我们必须先要计算出来最大的并且够减的那个 2k 。然后每次将y向右移动1位,去判断下一个是否够减,不够减的话继续移动。直到最后 x<y 即可。
算法2
其实可以二分一下z是多少,然后judge的时候利用快速加,原理同快速幂。时间复杂度为loglog
细节
用INT_MIN / -1的结果会溢出,应该处理。
代码
//algorithm1
#define LL long long
class Solution {
public:
int divide(int x, int y) {
if (y == 0) return INT_MAX;
LL nx = abs((LL)x), ny = abs((LL)y);
LL sum = 0, p = 1;
while (ny <= nx) ny <<= 1, p <<= 1;
while (nx >= abs((LL)y)) {
while (ny > nx) ny >>= 1, p >>= 1;
sum += p; nx -= ny;
ny >>= 1; p >>= 1;
}
sum = ((x > 0 && y > 0) || (x < 0 && y < 0)) ? sum : -sum;
return sum > INT_MAX ? INT_MAX : sum;
}
};
//algorithm2
#define LL long long
class Solution {
public:
LL quickAdd(LL x, LL n) {
if (n == 1) return x;
if (n == 0) return 0;
LL t = quickAdd(x, n >> 1);
if (n & 1) return t + t + x;
return t + t;
}
int divide(int x, int y) {
if (y == 0) return INT_MAX;
LL nx = abs((LL)x), ny = abs((LL)y);
LL l = 0, r = nx, m, ans = 0;
while (l <= r) {
m = l + (r - l >> 1);
if (nx - quickAdd(ny, m) >= ny) l = m + 1;
else r = m - 1, ans = m;
}
ans = ((x < 0 && y < 0) || (x > 0 && y > 0)) ? ans : -ans;
return ans > INT_MAX ? INT_MAX : ans;
}
};