问题描述
Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
问题本身很简单,就是不用乘除法和求余运算,完成简单的整数除法。(如果溢出,就返回 INT_MAX就好)。
思路1 – 原始思路
问题看起来很简单,我们只需要沿用整数除法的定义,逐次累加除数直至其刚好大于或者等于被除数 – 除数,结果就一目了然了。
当然这里说的是除数和被除数都是正整数的情况,那么当有一方或者两方为负数的时候,问题就不能简单这么解决了,不过也只需要存储一个两个运算成员符号的异或结果sign
,最后输出的时候 return sign ? result : -result
这样也就解决了。
上面说的思路,简单累加的话,就是一个O(N)的平均复杂度,对于某些问题来说,O(N)的复杂度完全是可以接受的,然而对于一个本来只需要一条 CPU 指令就可以搞定的问题来说,做成这个复杂度也实在是令人恼火。
不过还是先把代码写出来吧,看看能不能AC:
class Solution {
public:
int divide(int dividend, int divisor) {
if(!divisor || (dividend == INT_MIN && divisor == -1))
return INT_MAX;
if(!dividend)
return 0;
int result = 0, sum = 0;
bool sign = bool(dividend < 0) == bool(divisor < 0);
unsigned long long dividendabs = labs(dividend);
unsigned long long divisorabs = labs(divisor);
while(1) {
sum += divisorabs;
result ++;
if(sum == dividendabs)
break;
else if(sum > dividendabs) {
result --;
break;
}
}
return sign ? result : -result;
}
};
果然毫无意外的 TLE了(Time Limit Exceeded)。TLE的测试例是-2147483648,1
。诚然这个问题完全可以在入口值判断那里解决,然而如果测试例是2147483646,1
呢?估计也会超时吧。所以问题还是要从时间复杂度这个问题上解决。
思路2-跑快一点
直观地分析这个问题,看起来问题主要还是出在向结果靠近的速度太慢,如果我们不是线性地累加呢?如果我们每次都翻倍……?根据经验,一旦用这种方式接近,往往可以让问题降低到 O(logn) 的程度。
让我们换个思路,每个整数都能转化成若干个2的n次方之和,这种数则一共是log2(N)个,若是从最低位找起,则平均每次运行log2(N)/2次,就可以啦。
根据 divisor = dividend * result = dividend * (这些数之和)
,问题就可以解决啦~!而复杂度则正好是O(log(N) * log(N))
。
下面上代码:
class Solution {
public:
int divide(int dividend, int divisor) {
if(!divisor || (dividend == INT_MIN && divisor == -1) || (dividend == INT_MAX && divisor == 1))
return INT_MAX;
if(!dividend)
return 0;
int result = 0, sum = 0;
bool sign = bool(dividend < 0) == bool(divisor < 0);
long long dividendabs = labs(dividend);
long long divisorabs = labs(divisor);
while(divisorabs <= dividendabs) {
long long temp = divisorabs, doubles = 1;
while((temp << 1) <= dividendabs) {
temp <<= 1;
doubles <<= 1;
}
dividendabs -= temp;
result += doubles;
}
return sign ? result : -result;
}
};
最后AC了,结果嘛,还不错(逃