问题描述
给定一个被除数和除数(都是 int
类型),要求在不使用除法、乘法、求余运算的前提下,算出商。如果得出的结果超过 int
类型,则返回 -2147483648
(商小于 -2147483648 时)或 2147483647
(商大于 2147483647 时)。题目链接:**点我**
样例输入输出
输入:10 3
输出:3
输入:-7 3
输出:-2
输入:-2147483648 1
输出:2147483647
解释:在数学上,-2147483648 / 1 = -2147483648,但是这个结果超过 int 类型的存储范围,所以返回结果是 int 类型的最大值 2147483647
问题解法
此问题要求不能使用除法、乘法和求余运算,因此最简单的做法就是暴力相减,从被除数中一直减去除数,直到被除数小于除数,记录相减的次数,即使商。但是,这种做法超时了。
根据题目的提示,可以使用二分查找的思路进行求解。当一个数 A1
除以 2 后,其结果 A2
小于被除数B
时,说明 A1
除 B
的商是 1,如果 A2
大于被除数,说明 A1 / B
的商至少是 A2 / B
的商的两倍。顺着这个思路,可以一直将被除数除 2 后与除数进行比较,直到被除数小于除数时,记录相除的次数 n,此时可以根据相除的次数得到最小的商是 2^(n - 1)
,同时将最开始的被除数减去 除数 * 2^(n - 1)
得到新的被除数,将新的被除数与除数进行新的相除计算得到其结果,最后将这两个结果进行相加得到最终的商。由于整个过程是对 2 进行相除和相乘的操作,可以用相应的位运算进行代替,从而避免使用乘法和除法。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| class Solution { public int divide(int dividend, int divisor) { if (dividend == divisor) { return 1; } if (divisor == Integer.MIN_VALUE) { return 0; } int count = 0; int sign = 1; if (divisor < 0) { sign = -sign; divisor = -divisor; } if (dividend < 0) { sign = -sign; if (dividend == Integer.MIN_VALUE) { dividend += divisor; count++; } dividend = -dividend; } int quotient = dividePositiveNum(dividend, divisor); if (quotient > Integer.MAX_VALUE - count) { return sign > 0 ? Integer.MAX_VALUE : Integer.MIN_VALUE; }
count = count + quotient; return sign > 0 ? count: -count; } private int dividePositiveNum(int dividend, int divisor) { if (dividend < divisor) { return 0; } if (dividend == divisor) { return 1; } int powCount = -1; int tempDividend = dividend; while (tempDividend > divisor) { tempDividend = tempDividend >> 1; powCount++; }
int partQuotient = 1 << powCount; int partMultiNum = divisor << powCount; int remaindDividend = dividend - partMultiNum; return partQuotient + dividePositiveNum(remaindDividend, divisor); } }
|