Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
JAVA
方法一
控制好符号及边界条件,直接考虑循环使用被除数减去除数,统计循环次数即为结果,果然超时。
方法二
由于不能直接进行乘除和取余操作,所以直接考虑使用位操作符来运算,但是虽然知道位操作带来的乘除关系,但是不知道如何计算除法,只好看看其他人怎么做的。参考http://blog.youkuaiyun.com/linhuanmars/article/details/20024907,作者给出了一个忘了很多年的公式:一个整数可以表示成以2的幂为底的一组基的线性组合,即
num=a0∗20+a1∗21+a2∗22+...+an∗2n
所以可以将 an 理解为除数的倍数,即 an=kn∗divisor∗2n ,而 ∑ni=1(ki∗2i) 即为商。以51÷5为例:
51=1∗5∗20+1∗5∗21+0∗5∗22+1∗5∗23=1∗5+2∗5+8∗5
所以51÷5的商是10,其中2^0不算。这种方法的效率在前20%,可见数学是多么的有用~~~
public class Solution {
public int divide(int dividend, int divisor) {
if(divisor == 0){
return Integer.MAX_VALUE;
}
if(dividend == 0 ){
return 0;
}
if (dividend == divisor){
return 1;
}
//开始讲这个判断与dividend = 0 放在了一起,使用或的关系,后来发现这是不对的,因为当dividend = Integer.MIN_VALUE时结果应该是1.也是就是说要记着int型负数的绝对值会比正数大,所以一旦dividend != divisor而divisor == Integer.MIN_VALUE,则必有Math.abs(dividend) < Math.abs(divisor),此时商一定是0.
if(divisor == Integer.MIN_VALUE){
return 0;
}
int result = 0;
//这里的经验值得记一下,当被除数取反可能会导致溢出时,可以先将这个数做一次运算
if(dividend == Integer.MIN_VALUE){
if(divisor == -1){
return Integer.MAX_VALUE;
}
dividend += Math.abs(divisor);
++result;
}
if(divisor == -1){
return -dividend;
}
boolean negative = false;
if((dividend > 0 && divisor < 0) ||
(dividend < 0 && divisor > 0)){
negative = true;
}
dividend = Math.abs(dividend);
divisor = Math.abs(divisor);
int count = 1;
//刚开始写的时候用的是while(divisor <= dividend),后来发现当divisor移位运算后有可能溢出,导致死循环,于是改成了while(divisor << 1 <= dividend),心想dividend一定不会越界,只要比他小就没问题,但是发现当dividend很大时,divisor最后一次移位时可能直接越界变成负数,导致死循环,于是改成了现在这样。
while((divisor << 1 > 0) && (divisor << 1 <= dividend)){
divisor <<= 1;
count <<= 1;
}
while (count > 0){
if (divisor <= dividend){
dividend -= divisor;
result += count;
}else {
divisor >>= 1;
count >>= 1;
}
}
if(negative){
result = -result;
}
return result;
}
}