![95e54195b3c46771dd121a3df1287072.png](https://i-blog.csdnimg.cn/blog_migrate/0f09b69e4e683e17e160aafa24dd3416.jpeg)
给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
示例 1:
输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = truncate(3.33333..) = truncate(3) = 3
示例 2:
输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = truncate(-2.33333..) = -2
提示:
被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。
来源:力扣(LeetCode)
链接:力扣
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这是一道算法看起来很简单初等,但是在编程方面有难度的题目。
从整数除法的定义能够很容易地知道,我们可以用多次减法生成除法的效果。于是我们就有了最初的想法:把除法放到正整数范围内进行,使用一个循环不断地以除数为单位削减被除数,直到某一次余下的数小于除数中止,最终我们输出削减的次数作为答案即可。
然而,简单的思路没能写出简单的代码。再写出60行代码,嵌套了5层if else循环仍然报错后,我发现我的情况分类处理出现了问题。事实上,分类情况只需要考虑以下几个要点:
1.输出结果的正负性(注意异或的使用)
boolean isPositive = (dividend > 0)^(divisor < 0);
long result = isPositive? res(dvd, dvr):-res(dvd,dvr);
2.输出结果是否在存储范围内
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
return Integer.MAX_VALUE;
}
3.0作为被除数
if (dividend == 0) return 0;
写在一起,就是:
if (dividend == 0) return 0;
else {
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
return Integer.MAX_VALUE;
}
else return (int)result;
}
我额外多写了好几种特殊情况的处理,但后来我明白那是因为我的算法运算效率太低,并且不能处理整数很大时的边界情况。如果不改进我们的算法,在出现边界值与1相除时程序会因为运行时间太长中止。故而我们使用一个朴素的想法加快除法的速度:
让每次削减被除数的量都是上一次削减的两倍。
具体地说,我们让被除数第一次削减的量为除数,第二次为除数的二倍,第三次为除数四倍,第四次为八倍。。。直到某一次削减剩余的量小于下一次应当削减的量,此时输出削减次数与剩余量,将削减次数存储,对剩余量进行相同的“加倍削减”操作,求这个剩余量的削减次数。。。如此往复,直至剩余量小于除数为止。此时,输出所有存储的削减次数之和,此乃最终结果的绝对值。
注意,这里的加倍可以使用移位操作来实现。左移或右移操作本质上是对二进制代码表示的数字乘以2或除以2,然而乘法和除法均不允许使用,故而我们考虑使用作用上等价的移位来进行代替。
代码如下:
class Solution {
public int divide(int dividend, int divisor) {
long dvd = (Math.abs((long)dividend));
long dvr = (Math.abs((long)divisor));
boolean isPositive = (dividend > 0)^(divisor < 0);
long result = isPositive? res(dvd, dvr):-res(dvd,dvr);
if (dividend == 0) return 0;
else {
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
return Integer.MAX_VALUE;
}
else return (int)result;
}
}
public long res(long dvd, long dvr){
long temp = dvd;
long result = 0;
while (temp >= dvr) {
long para = 1;
while (temp - dvr * para > 0) {
para = para <<= 1;
}
if (temp == dvr) {
result += para;
temp = temp - dvr * para;
}
else {
para >>= 1;
result += para;
temp = temp - dvr * para;
}
}
return result;
}
}
最后,需要注意,我们使用了长整型long进行运算,以避免数据的溢出。