设有两个大整数相乘,X=61438521,Y=94736407.那么XY=5820464730934047.易知我么的算法需要O(N²)即O(8²)次操作.
如果我们把X和Y都拆成两半,由最高几位和最低几位组成.那么XL=6143,XR=8521,YL=9473,YR=6470.于是X=XL*10^4+XR,Y=YL*10^4+YR.可以得到
XY=XL*YL*10^8+(XL*YR+XR*YL)*10^4+XRYR
显然这个式子就是由4个乘法组成的,每一个都是原问题的一半,而10^8,10^4的乘法只是添一些0,于是可以得到递归:T(N)=4T(N/2)+O(N)..
我们按照主定理(相关资料查阅维基百科),可以求得算法复杂度仍然是O(N²).并没有改进这个问题.
观察XL*YR+XR*YL,可以分解为(XL-XR)(YR-YL)+XL*YL+XR*YR,我们仅需要算前面一项,后面的两项已经计算过了.于是得到了T(N)=3T(N/2)+O(N).,按照主定理,可得T(N)=O(N^1.59).当然对于每一个乘积我们还可以继续递归下去,一般到四位数就不用递归了.
代码:
public class BigMultiply {
//大整数相乘
public static String multiply(String x, String y) {
int flag1 = 0;//x的符号位
int flag2 = 0;//y的符号位
if (x.charAt(0) == '-') {//处理符号
x = x.substring(1);//先把符号位截掉
flag1 = 1;
}
if (y.charAt(0) == '-') {
y = y.substring(1);
flag2 = 1;
}
String flag = (flag1 ^ flag2) == 1 ? "-" : "";//相乘即异或之后符号位
if (x.length() < y.length())//保证x的位数更大
return flag + multiply(y, x);
if (x.length() <= 4)
return flag + Integer.parseInt(x) * Integer.parseInt(y);//少于等于四位数直接计算了
if (x.length() % 2 == 0) {//x位数是偶数 就把y补成和x一样长
while (x.length() > y.length())
y = "0" + y;
} else {//x位数不是偶数 就先把x补成偶数 再把y补成和x一样长
x = "0" + x;
while (x.length() > y.length())
y = "0" + y;
}
String xl = x.substring(0, x.length() / 2);
String xr = x.substring(x.length() / 2);
String yl = y.substring(0, y.length() / 2);
String yr = y.substring(y.length() / 2);
String D1 = minus(xl, xr);//xl-xr
String D2 = minus(yr, yl);//yr-yl
String xlyl = multiply(xl, yl);//xl*yl
String xryr = multiply(xr, yr);//xr*yr
String D3 = add(multiply(D1, D2) + "", add(xlyl, xryr));//D1*D2+Xl*Yl+Xr*Yr
return flag + add(shift(xlyl, x.length()), add(shift(D3, x.length() / 2), xryr)); //Xl*Yl*10^n+D3*10^(n/2)+Xr*Yr
}
//大数相减 带符号处理
public static String minus(String x, String y) {
int large = compare(x, y);
String flag = large >= 0 ? "" : "-";//加上符号
if (large == 0)
return "0";
else if (large > 0)//转化成大的减小的
return minusBigNum(x, y);
else
return flag + minusBigNum(y, x);
}
//大数相减
private static String minusBigNum(String x, String y) {//大数减小数
int len = x.length();
while (len > y.length())
y = "0" + y;
StringBuilder result = new StringBuilder();
int flag = 0;//表示是否进位
for (int i = len - 1; i >= 0; i--) {
int xs = Integer.parseInt(String.valueOf(x.charAt(i)));
int ys = Integer.parseInt(String.valueOf(y.charAt(i)));
if (xs + flag >= ys) {//别忘了把flag加上
result.append(xs - ys + flag);
flag = 0;
} else {
result.append(10 + xs - ys + flag);
flag = -1;
}
}
return clearZero(result.reverse().toString());
}
//大数相加
public static String add(String x, String y) {
if (x.charAt(0) == '-') {//先处理符号
x = x.substring(1);
if (y.charAt(0) == '-') {
y = y.substring(1);
return "-" + add(x, y);
} else
return minus(y, x);
}
if (y.charAt(0) == '-') {
y = y.substring(1);
return minus(x, y);
}
if (x.length() < y.length())
return add(y, x);//保证x的位数更大
int len = x.length();
while (len > y.length())//补位使位数相等
y = "0" + y;
StringBuilder result = new StringBuilder();
int flag = 0;//表示是否进位
for (int i = len - 1; i >= 0; i--) {
int xs = Integer.parseInt(String.valueOf(x.charAt(i)));
int ys = Integer.parseInt(String.valueOf(y.charAt(i)));
if (xs + ys + flag > 9) {//别忘了把flag加上
result.append(xs + ys - 10 + flag);
flag = 1;
} else {
result.append(xs + ys + flag);
flag = 0;
}
}
if (flag != 0)
result.append(1);
return clearZero(result.reverse().toString());
}
//计算10n次方的 就是后面加0
public static String shift(String x, int n) {
for (int j = 0; j < n; j++) {
x += "0";
}
return x;
}
//消除0
private static String clearZero(String str) {
int j = 0;
while (j < str.length() && str.charAt(j) == '0') {
j++;
}
return str.substring(j);
}
//比较两个数的大小
private static int compare(String x, String y) {
if (x.length() > y.length())
return 1;
else if (x.length() < y.length())
return -1;
else {
int index = 0;
while (index < x.length() && x.charAt(index) == y.charAt(index))
index++;
if (index == x.length())
return 0;
else {
return x.charAt(index) > y.charAt(index) ? 1 : -1;
}
}
}
public static void main(String[] args) {
System.out.println(multiply("-61438521", "94736407"));
System.out.println(multiply("-3124234254543411432432422238221342421",
"-2423442342342342342342342323423445345699"));
}
}
算法并不复杂,但是处理符号什么的还是比较麻烦的,而且加法减法啥的都要自己去实现.