力扣题目-字符串相乘

157 阅读6分钟

一、题目

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

注意: 不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

 

示例 1:

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

示例 2:

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

 

提示:

  • 1 <= num1.length, num2.length <= 200
  • num1 和 num2 只能由数字组成。
  • num1 和 num2 都不包含任何前导零,除了数字0本身。

二、解答

题目分析

本题的核心要求是实现两个以字符串形式呈现的非负整数的乘法运算,并且最终的乘积结果也要以字符串形式返回。同时,存在重要的限制条件,即不能运用任何内置的大整数库,也不能直接把输入的字符串转换为整数进行计算。

解题思路

由于不能直接将字符串转换为整数,我们需要模拟手工乘法的过程。具体步骤如下:

  1. 初始化结果数组:创建一个长度为 num1.length + num2.length 的数组,用于存储每一位相乘的结果。
  2. 逐位相乘:从 num1 和 num2 的最低位开始,逐位相乘,并将结果累加到结果数组的相应位置。
  3. 处理进位:遍历结果数组,处理每一位的进位。
  4. 去除前导零:去除结果数组前面的零。
  5. 转换为字符串:将结果数组转换为字符串。

示例分析

示例 1
  • 输入num1 = "2"num2 = "3"
  • 分析:在手工乘法中,我们直接将 2 和 3 相乘,得到 6。所以最终输出为 "6"
示例 2
  • 输入num1 = "123"num2 = "456"

  • 分析

    • 首先,将 123 拆分为 100 + 20 + 3,将 456 拆分为 400 + 50 + 6

    • 然后,进行乘法运算:

      • 3 * 6 = 18
      • 3 * 50 = 150
      • 3 * 400 = 1200
      • 20 * 6 = 120
      • 20 * 50 = 1000
      • 20 * 400 = 8000
      • 100 * 6 = 600
      • 100 * 50 = 5000
      • 100 * 400 = 40000
    • 最后,将所有结果相加:18 + 150 + 1200 + 120 + 1000 + 8000 + 600 + 5000 + 40000 = 56088。所以最终输出为 "56088"

代码

class Solution {
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }
        String ans = "0";
        int m = num1.length(), n = num2.length();
        for (int i = n - 1; i >= 0; i--) {
            StringBuffer curr = new StringBuffer();
            int add = 0;
            for (int j = n - 1; j > i; j--) {
                curr.append(0);
            }
            int y = num2.charAt(i) - '0';
            for (int j = m - 1; j >= 0; j--) {
                int x = num1.charAt(j) - '0';
                int product = x * y + add;
                curr.append(product % 10);
                add = product / 10;
            }
            if (add != 0) {
                curr.append(add % 10);
            }
            ans = addStrings(ans, curr.reverse().toString());
        }
        return ans;
    }

    public String addStrings(String num1, String num2) {
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        StringBuffer ans = new StringBuffer();
        while (i >= 0 || j >= 0 || add != 0) {
            int x = i >= 0 ? num1.charAt(i) - '0' : 0;
            int y = j >= 0 ? num2.charAt(j) - '0' : 0;
            int result = x + y + add;
            ans.append(result % 10);
            add = result / 10;
            i--;
            j--;
        }
        ans.reverse();
        return ans.toString();
    }
}

代码分析

代码功能概述

这段代码定义了一个 Solution 类,其中包含两个方法:multiply 和 addStringsmultiply 方法的作用是实现两个以字符串形式表示的非负整数的乘法运算,并且将结果也以字符串形式返回。addStrings 方法则用于实现两个以字符串形式表示的非负整数的加法运算,同样将结果以字符串形式返回。

方法详细分析

multiply 方法

java

public String multiply(String num1, String num2) {
    if (num1.equals("0") || num2.equals("0")) {
        return "0";
    }
    String ans = "0";
    int m = num1.length(), n = num2.length();
    for (int i = n - 1; i >= 0; i--) {
        StringBuffer curr = new StringBuffer();
        int add = 0;
        for (int j = n - 1; j > i; j--) {
            curr.append(0);
        }
        int y = num2.charAt(i) - '0';
        for (int j = m - 1; j >= 0; j--) {
            int x = num1.charAt(j) - '0';
            int product = x * y + add;
            curr.append(product % 10);
            add = product / 10;
        }
        if (add != 0) {
            curr.append(add % 10);
        }
        ans = addStrings(ans, curr.reverse().toString());
    }
    return ans;
}

  • 输入检查

    • 若 num1 或者 num2 为 "0",则直接返回 "0",因为任何数与 0 相乘结果都为 0。
  • 初始化结果

    • 把最终结果 ans 初始化为 "0"
  • 逐位相乘

    • 从 num2 的最低位开始遍历,对于 num2 的每一位:

      • 创建一个 StringBuffer 类型的 curr 用于存储当前位与 num1 相乘的结果。
      • 为了模拟乘法运算中每一位相乘结果的右移,在 curr 中添加相应数量的 0。
      • 把 num2 当前位的字符转换为整数 y
      • 从 num1 的最低位开始遍历,将 num1 当前位的字符转换为整数 x,计算 x 和 y 的乘积并加上进位 add,将结果的个位数添加到 curr 中,更新进位 add
      • 若最后还有进位,将进位添加到 curr 中。
  • 结果累加

    • 反转 curr 并将其转换为字符串,调用 addStrings 方法将其与之前的结果 ans 相加,更新 ans
  • 返回结果

    • 最终返回 ans
addStrings 方法

java

public String addStrings(String num1, String num2) {
    int i = num1.length() - 1, j = num2.length() - 1, add = 0;
    StringBuffer ans = new StringBuffer();
    while (i >= 0 || j >= 0 || add != 0) {
        int x = i >= 0 ? num1.charAt(i) - '0' : 0;
        int y = j >= 0 ? num2.charAt(j) - '0' : 0;
        int result = x + y + add;
        ans.append(result % 10);
        add = result / 10;
        i--;
        j--;
    }
    ans.reverse();
    return ans.toString();
}
  • 初始化变量

    • i 和 j 分别指向 num1 和 num2 的最后一位,add 用于存储进位,ans 是一个 StringBuffer 用于存储相加的结果。
  • 逐位相加

    • 只要 num1 或者 num2 还有未处理的位,或者进位不为 0,就继续循环:

      • 获取 num1 和 num2 当前位的数字,若已经遍历完则为 0。
      • 计算当前位的和以及进位,将和的个位数添加到 ans 中。
      • 更新 i 和 j,指向前一位。
  • 反转结果

    • 由于是从低位到高位依次添加结果,所以最后需要反转 ans
  • 返回结果

    • 将 ans 转换为字符串并返回。

三、总结

  1. 核心方法

    • multiply方法:通过模拟乘法运算,将num2逐位与num1相乘,再累加结果得到最终乘积。若任一输入为 "0",则直接返回 "0"
    • addStrings方法:实现两个字符串形式整数的加法,从低位到高位逐位相加并处理进位。
  2. 实现思路multiply方法借助addStrings方法累加每一位的乘法结果,模拟手动乘法过程;addStrings方法则通过循环逐位相加并处理进位

复杂度分析

  • 时间复杂度multiply 方法的时间复杂度为 O(m×n),其中 m 和 n 分别是 num1 和 num2 的长度。addStrings 方法的时间复杂度为 O(max(m,n))。
  • 空间复杂度:主要的空间开销在于存储中间结果和最终结果,空间复杂度为 O(m+n)。