整数除法
题目要求
输入2个int型整数,它们进行除法计算并返回商,要求不得使用乘号'*'、除号'/'及求余符号'%'。当发生溢出时,返回最大的整数值。假设除数不为0。例如,输入15和2,输出15/2的结果,即7。
有问题的方法
一上来就想到用减法的方法,直接一顿输出。
public class DivisionClass {
public static Integer DivisionMethod(Integer dividend, Integer divisor) {
Integer signNum = 0;
Integer quotient = 0;
if (divisor == 0) {
throw new RuntimeException("除数不能为0");
}
if (dividend == 0) {
return quotient;
}
if (Math.signum(dividend) == Math.signum(divisor)) {
//同符号则signNum为正
signNum = 1;
} else {
signNum = -1;
}
Integer pureDividend = Math.abs(dividend);
Integer pureDivisor = Math.abs(divisor);
while (pureDividend > 0) {
pureDividend = Math.subtractExact(pureDividend, pureDivisor);
if (pureDividend > 0) {
quotient++;
}
}
return quotient * signNum;
}
}
复制代码
很明显,问题多多!
问题一
题目中要求输入的是int类型,但是函数定义给的是输入两个Integer,这和题目中的要求不同
问题二
题目中要求不能使用乘除,但是在最后一个return quotient * signNum;
这里很不幸,忘记了这一点,使用了乘法。。。
问题三
大量使用了Math类中的方法,题目中倒也没说不行,但是后来看了解法之后,感觉还是少使用Math类中的方法更好 同时,对于Math类中的方法,使用中的坑还是不太注意 注意这里的Math.abs
Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative
representable int value, the result is that same value, which is negative.
复制代码
在它的注释里面有写当输入的是Integer.MIN_VALUE
的时候,返回的结果还是Integer.MIN_VALUE
,这里是因为 int的最大值是2的31次方-1(0x7fffffff),int的最小值是-2的31次方(0x80000000)
所以while (pureDividend > 0)
这里实际上就有问题了,当输入的是Integer.MIN_VALUE
的时候,直接不会走这个while,就会直接返回商为0
问题四
当被除数很大但除数很小时,减法操作执行的次数会很多。例如,求Integer.MAX_VALUE/1,减1的操作将执行2的31次方-1次,需要很长的时间。如果被除数是n,那么这种解法的时间复杂度为O(n)。所以我们可以将上述解法稍做调整。当被除数大于除数时,继续比较判断被除数是否大于除数的2倍,如果是,则继续判断被除数是否大于除数的4倍、8倍等。如果被除数最多大于除数的2k倍,那么将被除数减去除数的2k倍,然后将剩余的被除数重复前面的步骤。由于每次将除数翻倍,因此优化后的时间复杂度是O(logn)。
问题五
将负数转换成正数存在一个小问题。对于32位的整数而言,最小的整数是-2的31次方,最大的整数是2的31次方-1。因此,如果将-2的31次方转换为正数则会导致溢出。由于将任意正数转换为负数都不会溢出,因此可以先将正数都转换成负数,用前面优化之后的减法计算两个负数的除法,然后根据需要调整商的正负号。
正确的方法
public static int DivisionMethodWithOutBug(int dividend, int divisor) {
if (dividend == 0x80000000 && divisor == -1) {
return Integer.MAX_VALUE;
}
int negative = 2;
if (dividend > 0) {
negative--;
dividend = -dividend;
}
if (divisor > 0) {
negative--;
divisor = -divisor;
}
int result = divideCode(dividend, divisor);
return negative == 1 ? -result : result;
}
private static int divideCode(int dividend, int divisor) {
int result = 0;
while (dividend <= divisor) {
int value = divisor;
int quotient = 1;
while (value >= 0xc0000000 && dividend <= value + value) {
quotient += quotient;
value += value;
}
result += quotient;
dividend -= value;
}
return result;
}