思路:二分
乘法:用快速乘来替代。
除法:除以2用>>1来替代
mod:用不到
注意:(dividend / intdivisor)
1:如果除法结果溢出,那么需要返回 2^31-1作为答案。因此在编码之前,我们可以首先对于溢出或者容易出错的边界情况进行讨论:
dividend讨论:
(1)INT_MIN : 1 (ans越界:return INT_MIN) -1(最终结果越界:return INT_MAX)
(2)0 : return 0
2:对于一般的情况,根据除数和被除数的符号,需要考虑 4种不同的可能性。因此,为了方便编码,我们可以将被除数或者除数取相反数,使得它们符号相同。如果我们将被除数和除数都变为正数,那么可能会导致溢出。例如当被除数为 -2^31,它的相反数产生了溢出。因此可以考虑将被除数和除数都变为负数,这样就不会有溢出的问题,在编码时只需要考虑1种情况了。
3:二分来源(x y为负数 ,z为正数,z的取值范围为:1到INT_MAX)
x/y==z 转化为:yz>=x>(z+1)y, 问题转化为找最大的z,满足yz大于等于x!!!因此可以用二分。
4:我自己二分的写法习惯用()两个开区间来写,所以,看一下边界,发现INT_MAX得单独考虑下
dividend为INT_MAX : 1(return INT_MAX) -1(return -INT_MAX)
这样二分时右边界初始化可以初始为INT_MAX。
class Solution {
public:
//m*n大于等于a的话return true 否则false,n是正数
bool fast_cheng(int m, int n, int a) {
int ans = 0;
while (n) {
if (n & 1) {
if (ans < a - m) return false; //ans+m<a转换下,因为m为负数,ans+m可能会越界!!!
//上面,因为m是负数,所以ans若已经小于a,则直接返回false!!!
ans += m; //上面先判断再+=,怕ans+m越界!!!
}
if(n != 1) {
if (m < a - m) return false; //若更新后的m已经小于a,说明m*n肯定小于a,返回false!!!
m += m; //-2147483648 + -2147483648会越界,m+m应该大于a,小于直接return false!!!
}
n >>= 1;
}
return true;
}
int divide(int dividend, int divisor) {
if (dividend == INT_MIN) {
if (divisor == 1) return INT_MIN;
if (divisor == -1) return INT_MAX;
}
if (dividend == INT_MAX) {
if (divisor == 1) return INT_MAX;
if (divisor == -1) return -INT_MAX;
}
if (dividend == 0) return 0;
bool flag = true;
if (dividend > 0) {
dividend = -dividend;
flag = !flag;
}
if (divisor > 0) {
divisor = -divisor;
flag = !flag;
}
int l = 0, r = INT_MAX;
while (l + 1 < r) {
int mid = l + ((r - l) >> 1); //
if (fast_cheng(divisor, mid, dividend)) l = mid; //乘法->快速乘
else r = mid;
}
return (flag) ? l : -l;
}
};
易错点:
1:由于判断mid * divisor >= dividend,使用快速乘时要对mid进行移位,因为mid是正数,不能搞错了。
2:使用二分求mid时,/2可以用>>1来写。
3:易错点已经在上面的代码中注释。