[LeetCode] 29. 两数相除(java实现)
1. 题目
2. 读题(需要重点注意的东西)
思路(二进制优化):
主要思路是用减法,减出最后所需要的商,但是一个个减是肯定会超时的,那么怎么优化呢?
二进制优化:
可以考虑使用二进制
的方式来减,这就将所需减次数从n次缩小到了logn次:
设被除数为x,除数为y,则可以预处理出2^30^y、2^29^y、2^28^y、...、2^0^y
的值,然后从大到小去看每一项,即如果被除数x大于230y,则使得x = x - 230y,依次类推 229y、228y、…、20y,即可反推出商。
接下来给个例子辅助理解:
设有被除数为十进制数50,除数为9,预处理出22 * 9 = 36 , 21 * 9 = 18, 20 * 9 = 9
则有:
50 - 22 * 9 = 50 - 36 = 14
14 - 20 * 9 = 5
得到余数为5,商为22 + 20 = 5
代码实现步骤:
- 处理符号,如果x和y的符号不同,需要全部处理为正数,若符号不同,最后则需要在答案中加上一个负号。(注意,最小负数的绝对值比最大正数多1,因此最小的负数转为正数后可能会溢出,因此要用longlong来存储转换后的值)
- 计算 230y、229y、228y、…、20y的值
- 特判,若答案溢出,则返回 Integer.MAX_VALUE
3. 解法
---------------------------------------------------解法---------------------------------------------------:
class Solution {
public int divide(int x, int y) {
// 特判
if(x == -2147483648 && y == 1) return Integer.MIN_VALUE;
// 处理符号
int flag = 1;
if(x > 0 && y < 0 || x < 0 && y > 0) flag = -1;
long a = x,b = y;
if(a < 0) a = -a;
if(b < 0) b = -b;
// 预处理出2的各个次方乘y的结果
long[] exp = new long[31];
for(int i = 0;i < 31;i++) exp[i] = (1 << i) * b;
// 减出商
long res = 0;
for(int i = 30;i >= 0;i--){
if(a - exp[i] >= 0){
a -= exp[i];
res += (long)1 << i;
}
}
res = flag*res;
if(res > Integer.MAX_VALUE || res < Integer.MIN_VALUE) return Integer.MAX_VALUE;
return (int)res;
}
}
4. 可能有帮助的前置习题
5. 所用到的数据结构与算法思想
- 二进制优化
6. 总结
用二进制优化来使得时间复杂度优化为logn级,注意边界条件