贪心算法-大整数乘法/加法/减法

设有两个大整数相乘,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"));
    }
}

算法并不复杂,但是处理符号什么的还是比较麻烦的,而且加法减法啥的都要自己去实现.

    原文作者:大整数乘法问题
    原文地址: https://blog.csdn.net/yyl424525/article/details/56016690
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞