题目大意:实现两个整数的除法,不能用乘、除、取余操作,假如溢出了,返回INT_MAX。
思路:
1、首先考虑溢出的情况,用两种:除数为0的时候,被除数为INT_MIN、且除数为-1的时候。
2、最简单的思路:由除数n得到被除数m,可以用循环加法来得到。小于的时候,则加上一个除数,同时令计数器加1,直到大于被除数时,结束,返回计数器结果。但此方法效率过低,在被除数极大,而除数很小的时候,例当被除数INT_MAX,除数为1,则需要循环INT_MAX次,是极其低下的。因此没有考虑。
3、可以考虑循环的时候,对结果进行加倍。考虑23和2,:
第一次:2+2,第二次:4+4,第三次:8+8,第四次:16+16,此时大于23,则不进行加倍。
这是,23-16=7,可以转换为7/2的子操作:
第一次:2+2,第二次:4+4,大于7,则转换为3/2,的子操作。
根据思路3所解释的方法,可以大大降低复杂度。
在实现的时候,用了两种不同的形式,原因在于,我认为在第一轮循环过程中,计算的结果对于后面的循环求解有用,这样就可以减少计算的时间,因此用数组将除数的倍乘结果:2*n,4*n,8*n,16*n,32*n...保存了下来。
但实现得比较复杂,提交运行的时间为16ms:
class Solution {
public:
int divide(int dividend, int divisor) {
bool flag=false;
if(divisor==0)
return INT_MAX;
else if((dividend>0&&divisor<0)||(dividend<0&&divisor>0))
flag=true;
long long divi_d,divi_s;
divi_d=abs((long long)dividend);
divi_s=abs((long long)divisor);
if(divi_s>divi_d)
return 0;
long long m=divi_s;
long long i=1;
vector<long long> divi_mul;
divi_mul.push_back(divi_s);
while(m<=divi_d)
{
m=divi_mul.back()+divi_mul.back();
if(m<=divi_d)
{
i=i+i;
divi_mul.push_back(m);
}
}
long long mm=i;
long long x=divi_d-divi_mul.back();
while(x>=divi_s)
{
divi_mul.pop_back();
if(x>=divi_mul.back())
{
i=i+(mm>>1);
x=x-divi_mul.back();
}
mm=mm>>1;
}
mm=flag?-i:i;
if(mm>INT_MAX)
return INT_MAX;
else
return mm;
}
};
看运行时间分布,发现太慢了。抱着试试的心态,尝试了不保存结果,用位运算来处理写的代码,提交后时间为8ms。应该是用加法进行倍乘操作太慢了,并且有数组的动态插入和删除操作。位移运算果然是个高效的东西,代码如下:
class Solution {
public:
int divide(int dividend, int divisor) {
bool flag=false;
if(divisor==0)
return INT_MAX;
else if((dividend>0&&divisor<0)||(dividend<0&&divisor>0))
flag=true;
long long divi_d,divi_s;
divi_d=abs((long long)dividend);
divi_s=abs((long long)divisor);
long long m=divi_d;
long long i=0;
while(m>0)
{
long long x=divi_s;
long long temp=1;
while(x<=m)
{
x=x<<1;
temp=temp<<1;
}
m=m-(x>>1);
i=i+(temp>>1);
}
i=flag?-i:i;
if(i>INT_MAX)
return INT_MAX;
else
return i;
}
};