分治思想 大整数相乘

这个结果看起来也没什么特别的,如果按照我们分治的思想,转换为两位数相乘,之间能否有些关系呢? 
1234分为 12(高位)和34(低位);5678分为56(高位)和78(低位) 
高位*高位结果:12*56=672 
高位*低位+低位*高位:12*78+34*56=936+1094=2840 
低位*低位结果:34*78=2652 
这里要拼接了。需要说明的是,刚才我们提到两位数分解成一位数相乘的规则:超过一位数,需要进位。同理(这里就不证明了),两位数乘以两位数,结果超过两位数,也要进位。 
从低位开始:低两位:2652,26进位,低位保留52;中间两位,2840+26(低位进位)=2866,28进位,中位保留66;高位,672+28(进位)=700,7进位,高位保留00。再往上就没有了,现在可以拼接起来:最高位进位7,高两位00,中位66,低位52,最后结果:7006652。 

规律终于找到了!任意位数(例如N位整数相乘),都可以用这种思想实现:低位保留N位数字串,多余高位进位;高位要加上低位进位,如果超过N位,依然只保留N位,高位进位。(如果是M位整数乘以N位整数怎么办?高位补0,凑成一样位数的即可,不赘述。) 

这里附上代码,时间复杂度是T(n)=O(n^log3)=O(n^1.59),因为可能出现负数,所以对其进行了处理。代码有点长,因为要用字符串代替长整型。

package com.liheng.algorithm;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 大整数乘法
 * @author Maxy
 *
 */
public class BigIntMultiply
{

    //规模只要在这个范围内就可以直接计算了
    private final static int SIZE = 4;
    
    // 此方法要保证入参len为X、Y的长度最大值
    private static String bigIntMultiply(String X, String Y, int len)
    {
        // 最终返回结果
    	String SA_B,SD_C;
        String str = "";
        int flag=0;
        // 补齐X、Y,使之长度相同
        X = formatNumber(X, len);
        Y = formatNumber(Y, len);

        // 少于4位数,可直接计算
        if (len <= SIZE)
        {
            return "" + (Integer.parseInt(X) * Integer.parseInt(Y));
        }

        // 将X、Y分别对半分成两部分
        int len1 = len / 2;
        int len2 = len - len1;
        String A = X.substring(0, len1);
        String B = X.substring(len1);
        String C = Y.substring(0, len1);
        String D = Y.substring(len1);
     // 两字符串长度要相同
        int lenM = Math.max(A.length(), B.length());
        String A1 = formatNumber(A, lenM);
        String B1 = formatNumber(B, lenM);
        int a=Integer.parseInt(A1.substring(0, 1));
        int b= Integer.parseInt(B1.substring(0, 1));
        if(a>b)
        {
        	SA_B=dudcting(A1,B1);
        }
        else
        {
        	 SA_B = dudcting(B1,A1);
        	       flag++;
        }
         lenM = Math.max(A.length(), B.length());
        String C1 = formatNumber(C, lenM);
        String D1 = formatNumber(D, lenM);
        int c=Integer.parseInt(C1.substring(0, 1));
        int d= Integer.parseInt(D1.substring(0, 1));
        if(d>c)
        {
        	 SD_C=dudcting(D1,C1);
        }
        else
        {
        	 SD_C = dudcting(C1,D1);
        	    flag++;
        	       
        }
        lenM=Math.max(SA_B.length(), SD_C.length());
        String ABDC="";
        if(flag!=1)
        {
        ABDC = bigIntMultiply(SA_B, SD_C, lenM);
        }else
        {
        	ABDC = bigIntMultiply(SA_B, SD_C, lenM);
        }
        
        String AC = bigIntMultiply(A, C, len1);
        String BD = bigIntMultiply(B, D, len2);

        // 处理BD,得到原位及进位
        String[] sBD = dealString(BD, len2);

        // 处理AD+BC的和
        String ADBC = addition(AC, BD);
        String ABCD="";
        lenM = Math.max(ABDC.length(), ADBC.length());
        if(flag==1)
        {
            String ABDC1 = formatNumber(ABDC, lenM);
            String ADBC1 = formatNumber(ADBC, lenM);
            int a1=Integer.parseInt(ABDC1.substring(0, 1));
            int b1= Integer.parseInt(ADBC1.substring(0, 1));
            	 ABCD = dudcting(ADBC1,ABDC1);
        }
        else
        {
        	ABCD = addition(ABDC,ADBC);
        }
        flag=0;
        // 加上BD的进位
        if (!"0".equals(sBD[1]))
        {
            ABCD = addition(ABCD, sBD[1]);
        }

        // 得到ADBC的进位
        lenM = Math.max(len1, len2);
        String[] sABCD = dealString(ABCD, lenM);

        // AC加上ADBC的进位
        AC = addition(AC, sABCD[1]);

        // 最终结果
        str = AC + sABCD[0] + sBD[0];

        return str;
    }
    // 两个数字串按位加
    private static String addition(String ad, String bc)
    {
        // 返回的结果
        String str = "";

        // 两字符串长度要相同
        int lenM = Math.max(ad.length(), bc.length());
        ad = formatNumber(ad, lenM);
        bc = formatNumber(bc, lenM);

        // 按位加,进位存储在temp中
        int flag = 0;

        // 从后往前按位求和
        for (int i = lenM - 1; i >= 0; i--)
        {
            int t =
                flag + Integer.parseInt(ad.substring(i, i + 1))
                    + Integer.parseInt(bc.substring(i, i + 1));

            // 如果结果超过9,则进位当前位只保留个位数
            if (t > 9)
            {
                flag = 1;
                t = t - 10;
            }
            else
            {
                flag = 0;
            }

            // 拼接结果字符串
            str = "" + t + str;
        }
        if (flag != 0)
        {
            str = "" + flag + str;
        }
        return str;
    }
    // 两个数字串按位减
    private static String dudcting(String ad, String bc)
    {
        // 返回的结果
        String str = "";

        
        // 按位加,进位存储在temp中
        int flag = 0;

        // 从后往前按位求和
        for (int i = ad.length() - 1; i >= 0; i--)
        {
            int t =flag+Integer.parseInt(ad.substring(i, i + 1))-Integer.parseInt(bc.substring(i, i + 1));

            // 如果结果超过9,则进位当前位只保留个位数
            if (t <0)
            {
                flag = -1;
                t = t+10;
            }
            else
            {
                flag = 0;
            }

            // 拼接结果字符串
            str = "" + t + str;
        }
        if (flag != 0)
        {
            str = "" + flag + str;
        }
        return str;
    }
    // 处理数字串,分离出进位;
    // String数组第一个为原位数字,第二个为进位
    private static String[] dealString(String ac, int len1)
    {
        String[] str = {ac, "0"};
        if (len1 < ac.length())
        {
            int t = ac.length() - len1;
            str[0] = ac.substring(t);
            str[1] = ac.substring(0, t);
        }
        else
        {
            // 要保证结果的length与入参的len一致,少于则高位补0
            String result = str[0];
            for (int i = result.length(); i < len1; i++)
            {
                result = "0" + result;
            }
            str[0] = result;
        }
        return str;
    }

    // 乘数、被乘数位数对齐
    private static String formatNumber(String x, int len)
    {
        while (len > x.length())
        {
            x = "0" + x;
        }
        return x;
    }

    //测试桩
    public static void main(String[] args)
    {
        // 正则表达式:不以0开头的数字串
        String pat = "^[1-9]\\d*$";
        Pattern p = Pattern.compile(pat);

        // 获得乘数A
        System.out.println("请输入乘数A(不以0开头的正整数):");
        Scanner sc = new Scanner(System.in);
        String A = sc.nextLine();
        Matcher m = p.matcher(A);
        if (!m.matches())
        {
            System.out.println("数字不合法!");
            return;
        }

        // 获得乘数B
        System.out.println("请输入乘数B(不以0开头的正整数):");
        sc = new Scanner(System.in);
        String B = sc.nextLine();
        m = p.matcher(B);
        if (!m.matches())
        {
            System.out.println("数字不合法!");
            return;
        }
        System.out.println(A + " * " + B + " = "
            + bigIntMultiply(A, B, Math.max(A.length(), B.length())));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值