29.两数相除
本质可以二分,但二分两种。下面展示两种。
同时这题要注意的,也同样是我们大量问题的缩影,如何处理边界问题。如果归纳到我们的解题框架,也就是解题建模:
如何确定我们的答案空间。本题有问题的点在于边界会溢出,也就是Integer.MIN_VALUE/-1会越界。
我们一般考虑除法,都是使用两个正数来除,于是需要使用long来做临时存储。
然后考虑二分时候,有两种思路:
- 一种是直接二分求解答案,判断除数*答案是否满足条件。
- 利用迭代,我们可以做减法,依次减去2的(0,1,2,....,n)次方,同时依次加入答案,直到最后被减数小于减数
一般第二种更快,第二种的复杂度是o(lg(divdend/divisor))
第一种是o(log(divdend)*32)
第一种:
public int divide(int div, int divi) {
long dividend = div, divisor = divi;
int flag = (dividend ^ divisor) >= 0 ? 1 : -1;
dividend = Math.abs(dividend);
divisor = Math.abs(divisor);
if (divisor > dividend) return 0;
long left = 0, right = dividend;
while (left <= right) {
long mid = left + ((right - left) >> 1);
long k = mutipK(divisor, mid);
if (dividend >= k && dividend - k < divisor) {
if (flag * mid> Integer.MAX_VALUE) return Integer.MAX_VALUE;
else if (flag * mid < Integer.MIN_VALUE) return Integer.MIN_VALUE;
else return flag * (int) mid;
}
if (k < dividend) left = mid + 1;
else if (k > dividend) right = mid - 1;
}
return 0;
}
private long mutipK(long num, long k) {
long ans = 0;
for (int i = 0; i < 32; i++) {
if (((k >> i) & 1) == 1) {
ans += num;
}
num += num;
}
return ans;
}
第二种:
public int divide(int div, int divi) {
long dividend = div, divisor = divi;
int flag = (dividend ^ divisor) >= 0 ? 1 : -1;
dividend = Math.abs(dividend);
divisor = Math.abs(divisor);
if (divisor > dividend) return 0;
long ans = 0;
while (dividend>divisor) {
int t = 1;
long temp = divisor;
while (dividend >= temp) {
dividend -= temp;
ans += t;
temp <<= 1;
t <<= 1;
}
}
if (flag*ans>Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (flag*ans<Integer.MIN_VALUE) return Integer.MIN_VALUE;
return flag*(int)ans;
}