算法目标
快速计算两个整数相乘的结果。
例如,, 为整数(int),在不使用加法的前提下,计算 的结果。
算法思路
使用乘法分配律将乘法进行分解
举个例子来说明,计算 。
5 可以分解为
那么, 可以表示成:
其中, 可以通过二进制的位移运算快速计算:15 >> n
如何通过代码快速进行分解
下一个问题,我们如何知道应该将 5 分解为 和 呢?
其实很简单,了解二进制定义的可以不难看出,上面的分解方法,就是 5 的二进制表示:0101
那么代码写起来就比较简单了,只需要一位一位的计算 2 的乘法,然后再求和即可,2 的乘法又可以用二进制移位运算实现。
边界条件
正负号的处理
为了简单,我们在计算 时,不是一般性的假设 ,并且 , 。
如果不是的话,可以交换 A、B 的值,单独计算正负号。
为什么将 A 当作负号、B 当作正号呢,因为这样相乘的结果也是负数,而整数的表示负数比正数多一个值。
代码实现
public int quickTimes(int a, int b) {
if (a == 0 || b == 0) {
return 0;
}
// |a| >= |b|
if (Math.abs(a)) < Math.abs(b)) {
int tmp = a;
a = b;
b = tmp;
}
if (b == 1) {
return a;
}
if (b == -1) {
if (a == Integer.MIN_VALUE) {
return Integer.MAX_VALUE;
}
return -a;
}
if (a == Integer.MIN_VALUE) {
return b > 0 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
// a < 0, b > 0
boolean reverse = false;
if (a > 0) {
a = -a;
reverse = !reverse;
}
if (b < 0) {
b = -b;
reverse = !reverse;
}
int res = 0;
int add = a;
while (b > 0) {
if ((b & 1) != 0) {
// 需要判断是否溢出
if (Integer.MIN_VALUE - res > add) {
res = Integer.MIN_VALUE;
break;
}
res += add;
}
if (b != 1) {
// 需要判断是否溢出
if (Integer.MIN_VALUE - add > add) {
res = Integer.MIN_VALUE;
break;
}
add += add;
}
}
if (reverse) {
return res == Integer.MIN_VALUE ? Integer.MAX_VALUE : -res;
}
return res;
}