大数相乘

近期看的算法比较杂,在博客上简单记录一下吧。大数相乘貌似在很多公司的面试中都有问过。

问题描述:

输入两个整数,要求输出这两个数的乘积。输入的数字可能超过计算机内整形数据的存储范围。

乘数A和B分别存放在字符串里,输出结果也存放在字符串中。

问题分析:

首先,考虑类似0000000123456789这样数字输入,为了避免不必要的计算,可以对输入字符串进行预处理preProcess,把前缀为0的字符串简化为从第一个不为零的数字开始的字符串。

其次,考虑输出字符串的长度,假设A的长度为a,B的长度为b,则两者相乘的长度为a + b - 1或者a + b。

第三,注意char和int之间的相互转化,char c转int a的方法:a = c - '0'或 a = c - 48,int a转char c的方法:c = (char) (a + 48)

然后,每次用一个数的一位与另一个数从低至高依次相乘,并与结果上的该位相加,动态更新结果。这个过程需要有addFlag和multiFlag来记录上次运算的加法进位和乘法进位。

最后,同样使用preProcess将结果最高位的0去掉。

public class Multiple {
    public String multiple(String A, String B) {
        String A1 = preProcess(A);
        String B1 = preProcess(B);
        char[] c1 = A1.toCharArray();
        char[] c2 = B1.toCharArray();
        char[] rst = new char[c1.length + c2.length];
        for (int i = 0; i < rst.length; i++) {
            rst[i] = '0';
        }
        reverse(c1, 0, c1.length - 1);
        reverse(c2, 0, c2.length - 1);
        for (int i = 0; i < c1.length; i++) {
            int addFlag = 0;
            int multiFlag = 0;
            for (int j = 0; j < c2.length; j++) {
                int temp1 = (c1[i] - 48) * (c2[j] - 48) + multiFlag;
                multiFlag = temp1 / 10;
                temp1 = temp1 % 10;
                int temp2 = rst[i + j] - 48 + temp1 + addFlag;
                addFlag = temp2 / 10;
                rst[i + j] = (char) (temp2 % 10 + 48);
            }
            rst[i + c2.length] = (char) (addFlag + multiFlag + 48);
        }
        reverse(rst, 0, rst.length - 1);
        return preProcess(new String(rst));        
    }
    public void reverse(char[] c, int start, int end) {
        while (start < end) {
            char temp = c[start];
            c[start] = c[end];
            c[end] = temp;
            start++;
            end--;
        }
    }
    public String preProcess(String s) {
        char[] c = s.toCharArray();
        int i = 0;
        while (i < c.length) {
            if (c[i] == '0') {
                i++;
                continue;
            } else {
                break;
            }
        }
        if (i == c.length) {
            return new String("0");
        }
        return new String(c, i, c.length - i);
    }
}

test case试过了“0000”*“00”,“999999”*“99”,“0011”*“01”这样的边界case,都没有问题。

这里的乘法默认是非负数相乘,若为负数相乘,只需要预先判断第一位,最后在结果加上相应符号即可。

 

posted on 2016-12-19 18:13  ShinningWu  阅读(265)  评论(0编辑  收藏  举报

导航