在问 · 算法题解

43. 字符串相乘

中等字符串按位相乘累加到结果数组力扣原题 ↗

题目描述

输入两个用字符串表示的非负整数 num1 和 num2。

计算它们的乘积,并同样以字符串形式返回。

不能使用内置的大整数库(如 BigInteger),也不能直接把输入字符串转成整数再计算。

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

解释:2 × 3 = 6。

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

解释:123 × 456 = 56088。

数据范围

  • 1 <= num1.length, num2.length <= 200
  • num1 和 num2 只含数字字符。
  • 除了数字 0 本身,两个数都没有前导零。

解题思路:按位相乘累加到结果数组

模拟竖式乘法。长 m 和 n 的两个数相乘,结果至多 m+n 位,开一个 res 数组。num1[i] × num2[j] 的乘积落在 res[i+j](十位)和 res[i+j+1](个位)上。从低位到高位枚举每一对数字:把乘积加上 res[i+j+1] 原有的值,个位写回 res[i+j+1],进位加到 res[i+j]。最后去掉前导 0(至少保留一位)。

为什么正确

处理完若干对 (i, j) 后,把 res 当作一个十进制数来读(允许某些位暂时 ≥ 10),它等于已处理的部分积之和。

复杂度分析

时间 O(m·n);空间 O(m+n)。

易错点

乘积要加上 res[i+j+1] 原有的值再拆个位和进位,否则会丢掉前面累加的结果。去前导 0 时要至少保留一位,否则 "0" × "52" 会返回空串。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def multiply(self, num1: str, num2: str) -> str:
        m, n = len(num1), len(num2)
        res = [0] * (m + n)
        for i in range(m - 1, -1, -1):
            for j in range(n - 1, -1, -1):
                p = int(num1[i]) * int(num2[j]) + res[i + j + 1]
                res[i + j + 1] = p % 10
                res[i + j] += p // 10
        k = 0
        while k < m + n - 1 and res[k] == 0:
            k += 1
        return ''.join(map(str, res[k:]))

载入编辑器,自己跑一遍 →

其他解法

竖式加法先算整行部分积,再逐行相加;按位相乘法利用“第 i 位 × 第 j 位只影响结果第 i+j、i+j+1 位”的规律,省去中间字符串,常数更小。

解法 2:竖式逐行相乘再做字符串加法 时间 O(mn + n²),空间 O(m+n)

完全模拟手算竖式:从右往左取 num2 的每一位 y,用 num1 乘以这一位得到一行部分积(带进位),并在末尾补上与该位位置对应个数的 0。再用第 415 题的“字符串相加”把这一行加到累计答案上。任一数为 "0" 时直接返回 "0",避免出现前导零。

和手算过程一一对应,最容易理解,并且复用了字符串加法。缺点是每一行都要生成新字符串并做一次完整的加法,补零和反复拼接带来额外的 O(n²) 开销和常数;主解法把 num1[i]×num2[j] 直接累加到结果数组的 i+j 和 i+j+1 位置,只遍历一次。

class Solution:
    def multiply(self, num1: str, num2: str) -> str:
        if num1 == "0" or num2 == "0":
            return "0"

        def add(a, b):
            i, j, carry, out = len(a) - 1, len(b) - 1, 0, []
            while i >= 0 or j >= 0 or carry:
                x = int(a[i]) if i >= 0 else 0
                y = int(b[j]) if j >= 0 else 0
                s = x + y + carry
                out.append(str(s % 10))
                carry = s // 10
                i -= 1
                j -= 1
            return ''.join(reversed(out))

        ans = "0"
        m, n = len(num1), len(num2)
        for j in range(n - 1, -1, -1):
            y = int(num2[j])
            cur = ['0'] * (n - 1 - j)
            carry = 0
            for i in range(m - 1, -1, -1):
                p = int(num1[i]) * y + carry
                cur.append(str(p % 10))
                carry = p // 10
            if carry:
                cur.append(str(carry))
            ans = add(ans, ''.join(reversed(cur)))
        return ans

字符串 专题的其他题目

查看 字符串 全部题目 →