43. 字符串相乘

题目

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

说明:

num1 和 num2 的长度小于110。
num1 和 num2 只包含数字 0-9。
num1 和 num2 均不以零开头,除非是数字 0 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。

解法

  1. a*b = b个a相加

思路很简单,有了ListNode相加的基础,代码整体不难。但需要从char变成数字,再变为char,略麻烦,且!尽管num1和num2的长度小于110,貌似仅需做110次运算,但实际上!运算次数超过110^2,直接爆炸。

  1. 细分乘法

来自leetcode评论区:

index:    0 1 2 3 4  

              1 2 3
          *     4 5
          ---------
                1 5
              1 0
            0 5
          ---------
            0 6 1 5
              1 2
            0 8
          0 4
          ---------
          0 5 5 3 5

故可以推测出:

  1. 对于num1的第i位*num2的第j位,其对应的是相乘后结果的第[i+j]和[i+j+1]位。
  2. 对于对于两个长度分别为len1和len2的数相乘后的结果位数最大为[len1+len2];

代码如下:

class Solution {
    public String multiply(String num1, String num2) {
        if(num1.equals("0") || num2.equals("0")){
            return "0";
        }else{
            int [] sum = new int [num1.length()+num2.length()];
            for(int i=0; i<num1.length(); i++){
                for(int j=0; j<num2.length(); j++){
                    int add = Character.getNumericValue(num1.charAt(i)) * Character.getNumericValue(num2.charAt(j));
                    int ge = add % 10;
                    int shi = add / 10;
                    int temp1 = sum[i+j+1] + ge;
                    int temp2 = sum[i+j] + shi;

                    sum[i+j+1] = temp1 % 10;
                    sum[i+j] = (temp2 + temp1 / 10) % 10;
                    int C = (temp2 + temp1 / 10) / 10;
                    int fir = i+j;
                    while(C>0 && fir>0){
                        temp1 = sum[fir-1] + C;
                        sum[fir-1] = temp1 % 10;
                        C = temp1 / 10;
                        fir--;
                    }  
                }
            }
            StringBuilder builder = new StringBuilder();
            for(int i=0;i<num1.length()+num2.length();i++){
                builder.append(String.valueOf(sum[i]));
            }
            return builder.toString().replaceFirst("^(0+)", "");
        }
    }
}

显然有点麻烦。原因在于上述代码是手推代码的倒推顺序,不得不考虑向前进位x个。

如果按照手推代码的顺序,就只需考虑[i+j-1]的进位(如果存在的话),

如下:

class Solution {
    public String multiply(String num1, String num2) {
        if(num1.equals("0") || num2.equals("0")){
            return "0";
        }else{
            int [] sum = new int [num1.length()+num2.length()];
            for(int i=num1.length()-1; i>=0; i--){
                for(int j=num2.length()-1; j>=0; j--){
                    int add = Character.getNumericValue(num1.charAt(i)) * Character.getNumericValue(num2.charAt(j));

                    int temp1 = sum[i+j+1] + add % 10;
                    int temp2 = sum[i+j] + add / 10;

                    sum[i+j+1] = temp1 % 10;
                    sum[i+j] = (temp1 / 10 + temp2) % 10;

                    int C = (temp1 / 10 + temp2) / 10;
                    
                    if(C>0){
                        sum[i+j-1] += C;
                    }
                }
            }

            StringBuilder builder = new StringBuilder();
            for(int i=0;i<num1.length()+num2.length();i++){
                builder.append(String.valueOf(sum[i]));
            }
            return builder.toString().replaceFirst("^(0+)", "");
        }
    }
}

可以看到,for循环并不是很丝滑,原因是没有考虑到乘法第k步和第k+1步错位的关系,

        for(int i = num1.length()-1; i >= 0; i--) {
            for(int j = num2.length()-1; j >= 0; j--) {
                int bitmul = (num1.charAt(i)-'0') * (num2.charAt(j)-'0');      
                bitmul += mul[i+j+1]; // 先加低位判断是否有新的进位
                
                mul[i+j] += bitmul / 10;
                mul[i+j+1] = bitmul % 10;
            }
        }

完美

posted @ 2022-01-16 15:25  啤酒加点醋  阅读(59)  评论(0)    收藏  举报