题目:Divide two integers without using multiplication, division and mod operator.If it is overflow, return MAX_INT.
首先,题目要求计算两个数相除的结果
其次,不能使用乘法、除法和模运算;如果结果溢出直接返回MAX_INT。
根据题目的限制,首先可能想到使用减法,循环用被除数减除数,知道小于0为止,但是这样对于很大的被除数肯定超时了(如2147483647除以1)。
可以使用移位运算,在Java中有三种移位运算
- << : 左移运算符,num << 1,相当于num乘以2
- >> : 右移运算符,num >> 1,相当于num除以2
- >>> : 无符号右移,忽略符号位,空位都以0补齐
注意运算符都在操作数的右侧
该题使用移位运算符的思路其实和使用减法相同,不过提高了效率(注意符号的处理,可以先保存符号位,然后将取两个数的绝对值计算):
- 每次将divisor左移shift位,得到最接近(小于)dividend的最大的数maxCloset,该数与divisor的商构成了最终商的一部分
- 使用dividend减去maxCloset后继续步骤1,直到dividend小于divisor
注意,对于可能出现的溢出,需要首先将操作数转换为long类型,同时程序中使用的数据类型尽量为long类型。最后类型转换前,也需要判断是否会溢出。
代码如下:
public class Solution {
public int divide(int dividend, int divisor) {
long dividendLong = dividend;
long divisorLong = divisor;
//可能的极端情况
if(divisorLong == 0)
return Integer.MAX_VALUE;
if(dividendLong == 0)
return 0;
//保存结果商
long trade = 0;
int sign = 1;//计算符号位
if((dividendLong < 0) ^ (divisorLong < 0))
sign = -1;
//取绝对值,如果使用int,这里可能出现溢出
dividendLong = Math.abs(dividendLong);
divisorLong = Math.abs(divisorLong);
while(dividendLong >= divisorLong){
int shift = 0;//左移位数
long part = 1;//部分商
while(divisorLong<<shift < dividendLong) {
++shift;
part <<= 1;
}
if(dividendLong == divisorLong<< shift) {
//如果相等,则直接跳出
trade += part;
break;
}
//不相等,需要向右移位,取maxCloset
trade += part >> 1;
dividendLong -= divisorLong << (shift-1);
}
//最后判断是否存在溢出
if(trade*sign > Integer.MAX_VALUE || trade*sign < Integer.MIN_VALUE)
return Integer.MAX_VALUE;
else
return (int)trade*sign;
}
}