题目:
Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
链接:https://leetcode.com/problems/divide-two-integers/#/description
4/13/2017
没做出来,时间超了
以下是我没做出来的答案,通不过OA
1 public class Solution { 2 public int divide(int dividend, int divisor) { 3 if (divisor == 0) return Integer.MAX_VALUE; 4 if (dividend == 0 || dividend > 0 && divisor > 0 && dividend < divisor || dividend < 0 && divisor < 0 && dividend > divisor) return 0; 5 if (divisor == 1) return dividend; 6 else if (divisor == -1) { 7 if (dividend == Integer.MIN_VALUE) return Integer.MAX_VALUE; 8 return -dividend; 9 } 10 if (dividend == divisor) return 1; 11 else if (dividend == -divisor) return -1; 12 13 int sign = 1; 14 15 if (dividend > 0 && divisor < 0) { 16 divisor = -divisor; 17 sign = -1; 18 } else if (dividend < 0 && divisor > 0) { 19 dividend = -dividend; 20 sign = -1; 21 } 22 23 int initDivisor = divisor; 24 int quotient = 0; 25 int times = 0; 26 27 while (dividend >= initDivisor) { 28 while (dividend > divisor) { 29 divisor <<= 1; 30 if (times == 0) times = 1; 31 else times <<= 1; 32 } 33 quotient += times; 34 dividend -= divisor >> 1; 35 divisor = initDivisor; 36 times = 0; 37 } 38 return sign == 1? quotient: -quotient; 39 } 40 }
需要再研究这道题,可以参考:
http://www.cnblogs.com/yrbbest/p/4435159.html
别人的做法,很喜欢这么详细的解释。
不过要注意他在中间把signed int变成了unsigned int解决了中间计算溢出的问题,我认为最好还是不要这么做。
we assure the factor
ret
's binary fomula is
ret = a0 + a1*2 + a2*2^2 + ...... + a29*2^29 + a30*2^30 + a31*2^31; ai = 0 or 1, i = 0......31
the dividend
B
and divisorA
is non-negative, then
A(a0 + a1*2 + a2*2^2 + ...... + a29*2^29 + a30*2^30 + a31*2^31) = B; Eq1
(1) when
Eq1
divided by2^31
, we can getA*a31 = B>>31
; thena31 = (B>>31)/A
;if
(B>>31) > A
, thena31 = 1
; elsea31 = 0
;(2) when
Eq1
divided by2^30
, we can getA*a30 + A*a30*2 = B>>30
; thena30 = ((B>>30) - a30*A*2)/A
; and(B>>30) - a31*A*2
can be rewritten by(B-a31*A<<31)>>30
, so we makeB' = B-a31*A<<31
, the formula simplified toa30 = (B'>>30)/A
if
(B'>>31) > A
, thena30 = 1
; elsea30 = 0
;(3) in the same reason, we can get
a29 = ((B-a31*A<<31-a30*A<<30)>>29)/A
, we makeB'' = B' - a30*A<<30
, the formula simplified toa29 = (B''>>29)/A
;do the same bit operation
32
times, we can geta31 ..... a0
, so we get theret
finally.the C solution with constant time complexity
1 int divide(int dividend, int divisor) { 2 //special cases 3 if(divisor == 0 || (dividend == INT_MIN && divisor == -1)) 4 return INT_MAX; 5 6 // transform to unsigned int 7 bool sign = (dividend > 0)^(divisor > 0); 8 unsigned int A = (divisor < 0) ? -divisor : divisor; 9 unsigned int B = (dividend < 0) ? -dividend : dividend; 10 int ret = 0; 11 12 // shift 32 times 13 for(int i = 31; i >= 0; i--) 14 { 15 if((B>>i) >= A) 16 { 17 ret = (ret<<1)|0x01; 18 B -= (A<<i); // update B 19 } 20 else 21 ret = ret<<1; 22 } 23 24 if(sign) 25 ret = -ret; 26 27 return ret; 28 }
https://discuss.leetcode.com/topic/17600/32-times-bit-shift-operation-in-c-with-o-1-solution
更多讨论:
https://discuss.leetcode.com/category/37/divide-two-integers
4/27/2017
36ms, 97%
自己重新做了一遍并且参考别人的答案。
思路:
按照之前的意思,通过计算最高位的系数来算答案。
1. 当除数和被除数没有Integer.MIN_VALUE时,dividend, divisor都转化成positive来计算。
当前剩余dividend >>i 和divisor比较,如果大于divisor,答案*2 + 1,并且dividend减去divisor;如果小于divisor,答案*2,不做额外加减。最后一步通过最初的符号来判断
2. 当除数和被除数有一个是Integer.MIN_VALUE时
转化为positive会造成overflow,需要用负数来计算。
当除数divisor是Integer.MIN_VALUE,答案只有1(被除数也是MIN_VALUE)或者0(其他所有任何数)
其他情况,将divisor也变成负数,所以这时除数和被除数都是负数。
负数的判断,谁的值大,谁的绝对值小,根据第1中情况
当前剩余dividend >>i 和divisor比较,如果大于divisor,答案*2 + 1,并且dividend减去divisor;如果小于divisor,答案*2,不做额外加减。最后一步通过最初的符号来判断
当dividend >> i大于divisor时,其实当前高位应该是0,答案*2不做额外加减,当小于divisor时,dividend>>i绝对值大,当前高位应该是1,答案*2 + 1.
特别重要的一点,移位运算,建议强制加括号,运算级太低了。
第43行,注意,其实dividend的值是越来越大的(绝对值越来越小)不会溢出,因为divisor是负数,divisor << i变成了一个绝对值更大的负数。dividend的值也越来越从负的接近于0
1 public class Solution { 2 /** 3 * @param dividend the dividend 4 * @param divisor the divisor 5 * @return the result 6 */ 7 public int divide(int dividend, int divisor) { 8 // Write your code here 9 if (divisor == 0 || dividend == Integer.MIN_VALUE && divisor == -1) { 10 return Integer.MAX_VALUE; 11 } else if (dividend == 0) { 12 return 0; 13 } else if (divisor == 1) { 14 return dividend; 15 } else if (divisor == -1) { 16 return -dividend; 17 } 18 19 boolean isNegative = (dividend > 0)^(divisor > 0); 20 21 int ret = 0; 22 if (dividend != Integer.MIN_VALUE && divisor != Integer.MIN_VALUE) { 23 dividend = Math.abs(dividend); 24 divisor = Math.abs(divisor); 25 for (int i = 31; i >= 0; i--) { 26 if ((dividend >> i) >= divisor) { 27 ret = (ret << 1) + 1; 28 dividend -= (divisor << i); 29 } else { 30 ret <<= 1; 31 } 32 } 33 } else { 34 if (divisor == Integer.MIN_VALUE) { 35 return dividend == Integer.MIN_VALUE? 1: 0; 36 } 37 if (divisor > 0) { 38 divisor = - divisor; 39 } 40 for (int i = 31; i >= 0; i--) { 41 if ((dividend >> i) <= divisor) { 42 ret = (ret << 1) + 1; 43 dividend -= (divisor << i); 44 } else { 45 ret <<= 1; 46 } 47 } 48 } 49 return isNegative? -ret: ret; 50 } 51 }