/* * 29. Divide Two Integers * 2016-4-17 by Mingyang * 这个我们就得使用位运算。我们知道任何一个整数可以表示成以2的幂为底的一组基的线性组合, * 即num=a_0*2^0+a_1*2^1+a_2*2^2+...+a_n*2^n。 * 基于以上这个公式以及左移一位相当于乘以2,我们先让除数左移直到大于被除数之前得到一个最大的基。 * 然后接下来我们每次尝试减去这个基,如果可以则结果增加加2^k,然后基继续右移迭代,直到基为0为止。 * 因为这个方法的迭代次数是按2的幂直到超过结果, * 所以时间复杂度为O(logn) * int的绝对值,int里面有一个特殊的数字:-2147483648,它的绝对值或者相反数 2147483648是超出int的范围的, * 对于这一情况需要特殊处理。所以不能直接调用 divide(-dividend, divisor)或者divide(dividend, – divisor)。 * 也不能写 int dv = abs(dividend)。处理方式是使用long long来保存其绝对值 * 计算绝对值的时候要写 long long dv = abs((long long)dividens)的原因是, * abs()有两个重载版本,其中一个是abs(int),另外一个是abs(long),如果不进行显式转换, * 则调用abs(int),对-2147483648的返回结果仍是-2147483648 * 计算两个整数商的时候,有两种选择:将被除数dv右移或者将除数ds右移,循环终止条件是dv < ds。 * 以上代码选用了右移被除数dv。原因是:当dv最高位(除符号位外)为1时, * 左移ds可能因为小于dv而将ds的有效位从最左移出,既会使比较出错,也可能导致死循环。 * 最后,在return res这里,还是可能会出错的,但是就不在这段程序的考虑范围了,错误输入: -2147483648, - */ public int divide(int dividend, int divisor) { //handle special cases if(divisor==0) return Integer.MAX_VALUE; if(divisor==-1 && dividend == Integer.MIN_VALUE) return Integer.MAX_VALUE; //get positive values long pDividend = Math.abs((long)dividend); long pDivisor = Math.abs((long)divisor); int result = 0; while(pDividend>=pDivisor){ //calculate number of left shifts int numShift = 0; while(pDividend>=(pDivisor<<numShift)){ numShift++; } //dividend minus the largest shifted divisor result += 1<<(numShift-1);//这里用加,因为下面减去了曾经计算过的部分,所以用加 //至于为什么要用1往左移?因为假设两个是倍数关系,96处于3的话,3左移5位到96,那么结果也是1左移5位 pDividend -= (pDivisor<<(numShift-1)); } if((dividend>0 && divisor>0) || (dividend<0 && divisor<0)){ return result; }else{ return -result; } } /* * 这道题目也可以不用位运算 * 见一下大神的算法 * 每次减去那个数,然后减去以后除数乘以2,结果也乘以2. */ public int divide1(int dividend, int divisor) { long mul=1;long count=0; Boolean neg=false; if(((dividend>0)&&(divisor<0))||((dividend<0)&&(divisor>0))) neg=true; long a=Math.abs((long)dividend),b=Math.abs((long)divisor); long ori=b; while(a>=ori) { a=a-b; count+=mul; b=b<<1; mul=mul<<1; if(a<b){ b=ori; mul=1; } } if(neg) count*=-1; if(count>Integer.MAX_VALUE||count<Integer.MIN_VALUE) return Integer.MAX_VALUE; else return (int)count; }