1.题目
将两个整数相除,要求不使用乘法、除法和 mod 运算符。如果溢出,返回 2147483647
。
100
,除数 =
9
,返回
11
。
2.算法
这道题是关于数值运算的,比较容易想到的方法是用被除数减去除数,一直到0,如果商为n,则需要减n次,事件复杂度为n,有没有可以优化的方法呢,在网上看到有人用位运算来做这个我们就得使用位运算。我们知道任何一个整数可以表示成以2的幂为底的一组基的线性组合,即num=a_0*2^0+a_1*2^1+a_2*2^2+...+a_n*2^n。基于以上这个公式以及左移一位相当于乘以2,我们先让除数左移直到大于被除数之前得到一个最大的基。然后接下来我们每次尝试减去这个基,如果可以则结果增加加2^k,然后基继续右移迭代,直到基为0为止。因为这个方法的迭代次数是按2的幂直到超过结果,所以时间复杂度为O(logn),但是为了避免越界,要进行越界检测,越界检测如下:
1.如果除数为0,我们直接返回最大值
2.如果被除数为Integer.MIN_VALUE,除数为-1,则直接返回最大值,如果除数为Integer.MIN_VALUE,则直接返回1
3被除数为Integer.MIN_VALUE,除数不为上面两种情况,则让被除数加一个除数绝对值,在取被除数绝对值
public int divide(int dividend, int divisor) {
// Write your code here
if (divisor == 0) //当除数为0时,返回最大值
{
return Integer.MAX_VALUE;
}
boolean isNeg = (dividend^divisor) >>> 31 == 1;//检测符号位
int res = 0;
if (dividend == Integer.MIN_VALUE)
{
dividend += Math.abs(divisor); //为避免取绝对值溢出
if (divisor == -1)
{
return Integer.MAX_VALUE;
}
res++;
}
if (divisor == Integer.MIN_VALUE)
{
return res;
}
dividend = Math.abs(dividend);
divisor = Math.abs(divisor);
int digit = 0;
// 为什么是小于等于,例如5 / 2,此时digit为1,如果是小于则digit为0,下面就错了
while (divisor <= dividend>>1)
{
divisor <<= 1;
digit++;
}
//为什么是大于等于,如10 / 10 ,此时digit为0,下面正确,如果为大于则错
while(digit >= 0)
{
if (dividend >= divisor)
{
res += 1 << digit;
dividend -= divisor;
}
divisor >>= 1;
digit--;
}
return isNeg ? -res : res;
}
def divide(self, dividend, divisor):
# Write your code here
INT_MAX = 2147483647
if divisor == 0:
return INT_MAX
isNeg = dividend > 0 and divisor < 0 or dividend < 0 and divisor > 0
a, b = abs(dividend), abs(divisor)
res, shaft = 0, 31
while shaft >= 0:
if a >= b << shaft:
a -= b << shaft
res += 1 << shaft
shaft -= 1
if isNeg:
res = -res
if res > INT_MAX:
return INT_MAX
return res