一、概述
输入两个数a和b,输出a/b,去尾法保留整数。不许用乘或除或取余。
想半天不知道怎么做。只好去看discuss。原来是用了左移和右移。
然后自己做。铁孤儿题。边界条件一堆,快把我折磨出INT_MIN的PTSD了。
二、分析
1、我的代码
先考虑一下算法:
现在有a和b,不让用除号怎么除呢?我们有不用除号的除法啊,同样的,有不用乘号的乘法。这就是左移或右移。左移除二,右移乘二。我想到了这步,但是之后就卡住了。还是蠢。
实际上的算法应该是对b操作:
b*2,判断a和b的大小,要是a>b,继续乘2直到a<b。若a<b,b左移,记下这时左移的次数c,求出2^c。
然后a-b,赋值给a。直到最后a<b。
举例为28/4。
首先28>4,4*2=8;28>8,8*2=16;28>16,16*2=32;28<32,32/2=16。
从4到16,左移2次,2^2=4。
然后28-16=12。
12>4,4*2=8;12>8,8*2=16;12<16,16/2=8。
从4到8,左移1次,2^1=2。
然后12-8=4。
4=4,4*2=8;8>4,8/2=4。
从4到4,左移0次。2^0=1。
然后4-4=0。
0<4,退出。
4+2+1=7。结果为7。
简而言之,就是把a分解成b*2^x+b*2^y+......
最后的结果就是2^x+2^y+......
代码如下:
class Solution {
public:
int divide(int dividend, int divisor) {
long result=0;
int ex=0;
int sign=0;
if((dividend>0&&divisor>0)||(dividend<0&&divisor<0))
sign=0;
else
sign=1;
long _dividend;
if(dividend==INT_MIN)
_dividend=2147483648;
else
_dividend=abs(dividend);
long _divisor;
if(divisor==INT_MIN)
_divisor=2147483648;
else
_divisor=abs(divisor);
long tmp=_divisor;
while(_dividend>=_divisor)
{
if(tmp<=_dividend)
{
tmp=tmp<<1;
ex++;
}
else
{
tmp=tmp>>1;
ex--;
_dividend=_dividend-tmp;
tmp=_divisor;
result+=pow(2,ex);
ex=0;
}
}
if(result==2147483648&&sign==1)
return INT_MIN;
if(result>INT_MAX||result<INT_MIN)
return INT_MAX;
if(sign==0)
return result;
else
return -result;
}
};
关键就是判断是否溢出。这个情况太多了。
INT_MIN和1不溢出,和-1溢出。
但是我又是直接abs算的,abs(INT_MIN)会报错,因此只能直接赋值。
麻烦死了。
2、较好的方法
算法一样,看看人家怎么处理边界条件。
class Solution {
public:
int divide(int dividend, int divisor) {
if (dividend == INT_MIN && divisor == -1) {
return INT_MAX;
}
long dvd = labs(dividend), dvs = labs(divisor), ans = 0;
int sign = dividend > 0 ^ divisor > 0 ? -1 : 1;
while (dvd >= dvs) {
long temp = dvs, m = 1;
while (temp << 1 <= dvd) {
temp <<= 1;
m <<= 1;
}
dvd -= temp;
ans += m;
}
return sign * ans;
}
};
emmmm没比我好哪去,唯一的优点就是用了labs比我的abs好一些。
三、总结
辣鸡题。