[Leetcode] Divide Two Integers
大体的思想史使用折半。
dividend(被除数) 和 divisor(除数)
除数不断进行翻倍,这里使用加法而不是乘以2的操作,同时记录divisor的个数,同样可以使用加法实现,当大于dividend的时候,停止,并且输出当前统计的divisior的个数。
同时从dividend当中减去当前的对divisor翻倍的值。在此进行下面的while循环,停止条件
一、剩余的dividend为零
二、剩余的dividend小于divisor
这里对divisor为1或者-1的情况进行特殊处理。
但是这里有一个非常好的corner case
如果是divisor是-1,那么只需要对dividend取反就可以了,但是如果dividend是最小的负数,就会出现问题。
因为计算机当中的整数是使用补码表示的,而且负数的状态比正数多了一个,如果进行取反,就会发生很奇怪的事情:
-1*Integer.MIN_VALUE还是Integer.MIN_VALUE
0-Integer.MIN_VALUE也是Integer.MIN_VALUE
因为补码的最小负数表示是
1,000000
上面的乘以-1或者被0减实际上都是取反加一的一种变化,
0,111111 +1
变为
1,000000
所以得不到我们想要的最大值,
因此这样当作一种特殊情况对待
我的代码如下。
1 public class Solution { 2 public int divide(int a, int b) { 3 double dividend = a; 4 double divisor =b; 5 //////////////////////////very good corner case below 6 /* 7 我们知道负整数比正整数多了一个状态。两者的绝对值相差是一,但是如果使用这个负整数*-1,结果是得到了最大的正整数。但是我们按照常规的将两者转化为 8 正数在进行计算的方式,会溢出。因为最小的负数,转化为正数时,就已经超了。我们可以将其存在一个double当中,但是最后转化为int是也是会溢出的。 9 所以这是一个非常好的Corner case 10 如果a是最小的负整数,也就是Integer.MIN_INT 11 */ 12 if(Math.abs(b)==1){ 13 if(b>0) return a;//1 14 else{//-1 15 if(a>0){ 16 return 0-a; 17 }else if(a==Integer.MIN_VALUE){ 18 return Integer.MAX_VALUE; 19 }else{ 20 return a*b; 21 } 22 } 23 } 24 ////////////////////////very good corner case up 25 if(divisor==0||divisor==0) return 0; 26 int flag = dividend*divisor<0? -1:1; 27 28 dividend = Math.abs(dividend); 29 divisor = Math.abs(divisor); 30 31 int sum=0; 32 33 while(dividend!=0){ 34 if(dividend<divisor){ 35 return sum*flag; 36 } 37 //assure there at least one 38 double pre=divisor; 39 int precount=1; 40 double tmp=divisor; 41 while(tmp+tmp<dividend){ 42 pre=tmp+tmp; 43 tmp+=tmp; 44 precount=precount+precount; 45 } 46 47 if(tmp+tmp==dividend){ 48 return (precount+precount)*flag; 49 } 50 dividend=dividend-tmp; 51 sum=sum+precount; 52 } 53 return (int)(sum*flag); 54 } 55 }