[Leetcode 43 Multiply Strings]大数乘法,回到乘法本身的“最基础”去优化

大数乘法是笔试面试中经常会被考到的一个题目,它要求我们对超出long类型范围的大整数用字符串进行处理,加减乘除都会考到,我们先试着写一下大数加法的代码:

    // Add Big Integer
    public String add(String num1, String num2) {
        if(num2.length() > num1.length()){
            // return add(String num2, String num1);
            String t = num1;
            num1 = num2;
            num2 = t;
        }

        if(num2.equals("0")) return num1;

        char[] n1 = num1.toCharArray();
        char[] n2 = num2.toCharArray();
        String res = "";
        int d = 0;
        int i=n1.length-1, j=n2.length-1;

        for(;j>=0; i--, j--){
            int a = (n1[i]-'0') + (n2[j]-'0') + d;
            d = a / 10;
            res = "" + (a % 10) + res;
        }

        // when d==0 it could be optimized.
        for(;i>=0; i--){
            int a = (n1[i]-'0') + d;
            d = a / 10;
            res = "" + (a % 10) + res;
        }

        if(d>0) res = "" + d + res;
        return res;
    }

按照思维惯性,我们会把乘法拆成加法去做,注意以下几点
1、把String变成char数组处理更好,用较长的char数组储存结果最后再转成String是很好的选择
2、去掉前导0
3、个位加法进位最多进1
所以上述代码有很多可以优化的地方。

所以两个大数相乘就拆成了下述两步:
1、一个大数与另一个大数的每一位相乘(若干个第一个大数自身相加)
2、得到的结果补0位对齐后再相加
不贴代码了,大家都能理解这个意思。


但是这个题目的更好的解决方式是要回到乘法的“最基础“。让我们看一下下图(来自某大神):

[Leetcode 43 Multiply Strings]大数乘法,回到乘法本身的“最基础”去优化_第1张图片

这个竖式和咱们最开始学乘法时候的竖式是有区别的,它把一个数乘以另一个数的一位分得更细了。

public class Solution {
    public String multiply(String num1, String num2) {
        int m = num1.length(), n = num2.length();
        int[] pos = new int[m + n];

        for(int i = m - 1; i >= 0; i--) {
            for(int j = n - 1; j >= 0; j--) {
                int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0'); 
                int p1 = i + j, p2 = i + j + 1;
                int sum = mul + pos[p2];

                pos[p1] += sum / 10;
                pos[p2] = (sum) % 10;
            }
        }  

        StringBuilder sb = new StringBuilder();
        for(int p : pos) if(!(sb.length() == 0 && p == 0)) sb.append(p);
        return sb.length() == 0 ? "0" : sb.toString();
    }
}

读懂上图和代码要了解三件事情:
1、位数为m和n的两数相乘,结果的位数最多为m+n(99*9=891,999*99=98901),所以pos数组的长度为m+n
2、(关键)一个数的第i高位与另一个数的第j高位相乘,得到的两位数结果(此时个位1看成01),第一位应加在结果的第i+j高位,第二位应加在结果的第i+j+1高位。
3、结果需要跳过前导0

这三点看懂了,本题一下子就开朗了,只要在面试的时候画出图中的式子,并跟面试官说出上面三件事情,代码部分只是体力活了。

你可能感兴趣的:(leetcode)