昨天开始刷LeetCode,刚开始做的几个题都没有问题,思路都很流畅,知道遇到了Divide Two Integers这个题目。
Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
题目的描述很简单,就是在不使用乘法、除法和模运算的情况下实现两个整数的除法。看到这个题目我首先想到的思路是除数一直相加,直到大于被除数,那么相加的次数减1就是我们需要的结果。代码如下:
public static int divide(int dividend,int divisor){
int MAX_INT = 2147483647;
boolean isReverse = false;
int mDividend = dividend;
int mDivisor = divisor;
if(dividend<0){
isReverse = !isReverse;
mDividend = -dividend;
}
if(divisor<0){
isReverse = !isReverse;
mDivisor = -divisor;
}
if(mDividend==0)
return 0;
if(mDivisor==0)
return MAX_INT;
int result = 1;
int tmp = mDivisor;
while (!(mDividend<=tmp)) {
result++;
tmp+=mDivisor;
}
if(tmp>mDividend)
result--;
if(isReverse)
result = -result;
return result;
}
因为考虑到负数的问题,所以显得比较繁琐,事实上核心代码并没有很复杂。但是,在代码提交时报了
Time Limit Exceeded
仔细思考发现,这样子做效率确实比较低,假设被除数是max_int 2147483647,除数是1,那么我们就需要加2147483647次才能得到结果,效率太低了!那么该如何提高效率呢?二分法。以前每次都是加除数,知道大于除数,假如使用二分法的话,40/2,那么我们2+2<40,4+4<40,8+8<40,16+16<40,32+32>40,再对40-32=8重复上述操作,则可以得到结果。代码如下
/**
* 二分法
* @param dividend 被除数
* @param divisor 除数
* @return
*/
public static int divide(int dividend,int divisor){
int result = 0;
int MAX_INT = 2147483647;
boolean isReverse = false;
if(dividend<0){
isReverse = !isReverse;
dividend = -dividend;
}
if(divisor<0){
isReverse = !isReverse;
divisor = -divisor;
}
if(dividend==0)
return 0;
if(divisor==0)
return MAX_INT;
int tmp = divisor;
int tmpResult = 1;
int remainder = dividend;
while (remainder>=divisor) {
tmp = divisor;
tmpResult = 1;
while ((tmp+tmp)<=remainder) {
tmp = tmp+tmp;
tmpResult = tmpResult+tmpResult;
}
remainder = remainder - tmp;
result = result +tmpResult;
}
if(isReverse)
result = -result;
return result;
}
但是!但是!!使用二分法还超时!!!使用二分法了你还报超时!效率都已经提高那么多了!!!
天哪!!到底该怎么搞啊?莫非真的要使用位运算吗???如何搞啊????莫非要让我用位运算重新实现一次除法吗?????
好吧,我的错,主要是越界问题没考虑清楚。注意:有可能tmp+tmp越界,同时,当值为-2147483648时,对他取反也会有越界问题。bug修复完成后代码如下:
/**
* 二分法
* 我操,越界问题太蛋疼。
* @param dividend 被除数
* @param divisor 除数
* @return
*/
public static int divide(int dividend,int divisor){
long result = 0;
int MAX_INT = 2147483647;
boolean isReverse = false;
long mDividend = dividend;
long mDivisor = divisor;
if(dividend<0){
isReverse = !isReverse;
mDividend = -mDividend;
}
if(divisor<0){
isReverse = !isReverse;
mDivisor = -mDivisor;
}
if(mDividend==0)
return 0;
if(mDivisor==0)
return MAX_INT;
long tmp = mDivisor;
long tmpResult = 1;
long remainder = mDividend;
while (remainder>=mDivisor) {
tmp = mDivisor;
tmpResult = 1;
while ((tmp+tmp)<=remainder) {
tmp = tmp+tmp;
tmpResult = tmpResult+tmpResult;
}
remainder = remainder - tmp;
result = result +tmpResult;
}
if(isReverse)
result = -result;
if(result>0&&(int)result<0){
return MAX_INT;
}
return (int) result;
}
Accepted!