144/5= 28,不能用除号、乘号和取余的符号。
分析:
Brute Force: 用被除数减去除数,减几次结果就是几。
位运算:减法不够快,试探性的乘2来加快速度。
28是可以用二进制表示的 28 = 2^4+2^3+2^2
所以 144 = 5*(2^4)+5*(2^3)+5*(2^2), 也就是把5依次<< 4,3,2位 = 80,40,20
144-80-40-20 = 4
所以关键是找到80这个位置,也就是5向左shift4位
思路:
1)判断符号
2)处理特殊情况
dividend = 0 => 0
divisor = 0 => INT_MAX
divisor = 1;=> dividend
dividend = INT_MIN, divisor = -1 => overflow
divident = INT_MIN => 要把他处理成不越界的情况!因为后面要取绝对值。
记录位数,何时divisor再乘以2就超过dividend的一半了 , 也就是5*2*2*2*2=80的时候超过了144/2=72. 位数=4。
利用调整这个位数来累加结果。
注意!只有剩下的dividend还大于current divisor的时候才做减法。否则就一直等着,等到current divisor降下来。
比如144-80-40-20 = 4,此时要等待current divisor=10,5。 发现都不行再跳出。
4)返回结果:
因为不能用乘法所以不可以是res*sign。想要取负可以用(~res+1)。
时间复杂度:
BF: O(n)
位运算: 由于是考察以2为基底的数的计算。又是用位操作实现的。所以是O(logn)
Code (C++):
class Solution {
public:
int divide(int dividend, int divisor) {
if(divisor == 0) return INT_MAX;
if(divisor == 1) return dividend;
if(dividend == 0) return 0;
int res = 0;
int sign = 1;
if(dividend == INT_MIN)
{
if(divisor == -1) return INT_MAX;
dividend += abs(divisor);
<strong>res++; </strong>//因为最后res是按照正数算出来的。在最后return的时候才翻转过来!
}
if(divisor == INT_MIN) return res;
if((divisor < 0 && dividend > 0) || (divisor > 0 && dividend < 0)) sign = -1;
dividend = abs(dividend);
divisor = abs(divisor);
int tmp = divisor;
int digit = 0;
while((dividend >> 1) >= tmp)
{
digit++;
tmp = tmp<<1;
}
while(digit >= 0)
{
<strong>if(dividend >= tmp)</strong>
{
dividend = dividend - tmp;
res += 1<<digit;
}
tmp = tmp>>1;
digit--;
}
return sign == 1 ? <gs id="7c0030bc-5605-466b-bf77-10bdb9697f10" ginger_software_uiphraseguid="67fc0744-2e5c-4357-ba53-5515ba2941d2" class="GINGER_SOFTWARE_mark">res</gs><gs id="4799052b-7386-4652-a82c-de7b11dd733c" ginger_software_uiphraseguid="67fc0744-2e5c-4357-ba53-5515ba2941d2" class="GINGER_SOFTWARE_mark"> :</gs> (~res+1);
}