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

来源:互联网 发布:网站在线客服系统源码 编辑:程序博客网 时间:2024/04/29 19:18

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

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

0 0