【算法训练】LeetCode#29 两数相除
一、描述
29. 两数相除
给你两个整数,被除数 dividend
和除数 divisor
。将两数相除,要求 不使用 乘法、除法和取余运算。
整数除法应该向零截断,也就是截去(truncate
)其小数部分。例如,8.345
将被截断为 8
,-2.7335
将被截断至 -2
。
返回被除数 dividend
除以除数 divisor
得到的 商 。
注意:假设我们的环境只能存储 32 位 有符号整数,其数值范围是 [-2147483648, 2147483647]
。本题中,如果商 严格大于 2147483647
,则返回 2147483647
;如果商 严格小于 -2147483648
,则返回 -2147483648
。
示例 1:
输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = 3.33333.. ,向零截断后得到 3 。
示例 2:
输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = -2.33333.. ,向零截断后得到 -2 。
二、思路
不允许使用除法模拟除法,那应该是用减法做吧,但是看了眼数值范围,感觉可能会越界,不过先试一试吧。
显然不行,减法是可以得到结果的,但是循环次数太多了,看了一眼讨论,发现了一个可行方案,还是自己太菜。
虽然题中不允许使用乘法和除法,但是没有限制移位运算,因此可以通过左移右移的方式对结果进行逼近,然后再辗转相减。
三、解题
public class LeetCode29 {
public static void main(String[] args) {
System.out.println(divide(7,-3));
}
public static int divide(int dividend, int divisor) {
int ans = 0;
if (divisor == 0){
return 0;
}
int right = 2147483647;
int left = -2147483648;
if (dividend == left && divisor == -1){
return 2147483647; // 最坏结果
}
boolean flag = (dividend ^ divisor) < 0; // 判断是否异号
long dividendL = Math.abs((long)dividend);
long divisorL = Math.abs((long)divisor);
for (int i = 31 ; i >= 0 ; i--){
// 结果最大不超过2^31,因此从2^31开始尝试
if ( (dividendL>>i) >= divisorL){
// 当 dividend/2^i >= divisor时,2^i*divisor一定小于dividend,因此相减
dividendL -= divisorL<<i;
ans += 1<<i; // 2^i一定是组成结果的一部分
}
}
return flag ? -ans : ans;
}
}