leetcode-29两数相除
边界处理
这题也是以前看过没理解,倒过来看理解的。
- 首先越界可能只有一种,最小数除-1
- 考虑简单情况,除数为1和-1以及被除数为0的情况,可以直接返回结果
- 接下来考虑一般情况:先判断商的正负值,然后把两个数都转为负数,因为如果转为正数的话,INT_MIN会溢出。
- 接下来就是不断翻倍,直到不满足条件,然后递归求解,具体如下(特别要注意除数相加可能的溢出问题):
public int divide(int dividend, int divisor) {
int sign=1;
if(dividend>0&&divisor<0 || dividend<0&&divisor>0)
sign=-1;
int tmp=divisor;
if(divisor==0)
return 0;
if(divisor==-1){
if(dividend==Integer.MIN_VALUE)
return Integer.MAX_VALUE;
return -dividend;
}
if(divisor==1)
return dividend;
dividend=dividend>0?0-dividend:dividend;
divisor=divisor>0?0-divisor:divisor;
int i=0;
if(dividend<=divisor)
i=1;
else
return 0;
while(dividend<=divisor+divisor&&divisor+divisor<0){
i=i+i;
divisor=divisor+divisor;
}
if(sign==1)
return i+divide(dividend-divisor, tmp);
else
return 0-(i+divide(dividend-divisor, tmp));
}
另一种容易理解的拆分代码:
class Solution {
public int div(int a,int b){//a,b都为负数
int tmp=b;
if(a>b)
return 0;
int cnt=1;
while(a<=b+b&&b+b<0){//判断<0是因为防止负数相加溢出为正数
cnt+=cnt;
b+=b;
}
return cnt+div(a-b,tmp);
}
public int divide(int dividend, int divisor) {
int sign=1;//判断是否异号
if(dividend>0&&divisor<0 || dividend<0&&divisor>0)
sign=-1;
if(divisor==0)//特殊情况
return 0;
if(divisor==-1){//特殊情况
if(dividend==Integer.MIN_VALUE)//唯一一种溢出情况,负最大除-1
return Integer.MAX_VALUE;
return -dividend;
}
if(divisor==1)//特殊情况
return dividend;
dividend=dividend<0?dividend:0-dividend;//防止负最小转正最大时出错
divisor=divisor<0?divisor:0-divisor;//统一转为负数
return sign==1?div(dividend,divisor):0-div(dividend,divisor);
}
}
几个自我收获:
++ 正数最大值加1会变成负最小,负数最小减1会变成正最大。这是补码计算得出的,也叫做溢出。
++ 这题如果有记录翻倍的过程应该会更快,减少了递归次数,用空间换时间。
++ 左移一位也就是当前数翻倍(右边补0),这题的话就是将除数进行移位,因为每个位置的数都翻倍,和也会翻倍,不过要考虑溢出问题