题目描述
思路解析动画文字版
最直觉的笨办法:转成整数相乘再转回字符串。可题目里数字可能上百位,远超 long 的范围,一转就溢出、算出来是错的——所以只能逐位手算。
目标 · 大数相乘按竖式逐位算:既然不能转整数,就回到小学竖式:每一位分别相乘,再把每次的小结果按位置累加、处理进位。
开一个结果数组 · 最多 m+n 位:先想清楚结果有多长:m 位数乘 n 位数,最多 m+n 位。所以开一个长度 6 的数组(123、456 各 3 位),每个格子先放 0,用来逐位累加。
关键 · 第 i 位 × 第 j 位落在哪:竖式的核心规律:num1 的第 i 位 × num2 的第 j 位,乘积最多两位——个位落在结果的第 i+j+1 位,进位落在它左边的第 i+j 位。记住这个下标对应,就不会算错位置。
举例 · 3 × 6 = 18 放进去:举个例子:个位 3 × 个位 6 = 18。按规律,8 放到第 5 位、进位 1 加到第 4 位。其余八对数字(1·2·3 × 4·5·6 共 9 对)都这样乘、累加进对应格子。
灵魂动作 · 同一格被第二对继续累加:关键来了:接着算 3 × 5 = 15,它的个位也要落到第 4 位。可第 4 位刚才已被 3×6 的进位 1 占住——这一格要被第二对数字继续累加,不能直接覆盖。
灵魂动作 · 先加旧值再拆个位/进位:正确做法:先把新积 15 和这格旧值 1 相加得 total=16,再拆——个位 6 留在第 4 位、进位 1 送到第 3 位。这就是「先累加再取模」:旧的进位 1 没被冲掉,而是被一起算了进去。数组从 [0,0,0,0,1,8] 变成 [0,0,0,1,6,8]。
九对全乘完 · 逐位累加 + 进位:把 3 位 × 3 位共 9 对都乘一遍,每次都累加到对应位、满十就往前一位进。全部算完,结果数组是 [0,5,6,0,8,8]。
去前导 0 · 拼成字符串:最后把数组拼成字符串,跳过开头多余的 0(若结果就是 0 要保留一个),得到 "56088"——正是 123 × 456。
一句话本质:num1[i] × num2[j] 的两位结果,个位累加到 i+j+1、进位累加到 i+j,全部乘完再去前导 0。下标对应记牢,这题就稳了。
雷区实演 · 一格被两对数字砸中:为什么强调「先累加再取模」?看第 4 位:3×6 时它先被进位 1 占住。随后 3×5=15 落到第 4 位,加上原有进位 1 变成 16——必须 total = 新积 + 这格旧值 再拆个位/进位(留 6、进 1),否则旧的 1 就被冲掉、结果错。
边界三连:字符串大数的边界:特判 0、去前导 0、但别删光。
三个高频追问:长度 m+n、下标由来、能否省掉中间数组。
这题是「字符串大数运算」的原子操作。同骨架可迁移:LC415 字符串相加(只剩一层进位)、LC2 两数相加(链表版竖式)、LC67 二进制求和(进位阈值变 2)。想成体系刷可去 /leetcode-animation/ds?k=math 跟专题,或问 AI 助教「竖式模拟还有哪些变体」。
参考代码
class Solution: def multiply(self, num1, num2): if num1 == '0' or num2 == '0': return '0' 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): mul = int(num1[i]) * int(num2[j]) p1, p2 = i + j, i + j + 1 total = mul + res[p2] res[p2] = total % 10 res[p1] += total // 10 return ''.join(map(str, res)).lstrip('0') or '0'复杂度
- 时间复杂度:O(mn),每对数字相乘
- 空间复杂度:O(m+n),结果数组
可套用的代码模板
这才是可背的骨架(不是照抄上面的参考代码):四步——开 m+n 数组 → 双层从低位枚举 → 先累加再拆 个位/进位 → 去前导 0。digit/strip 两个挖空换成具体取字符与拼接即可,加法 (LC415) 同骨架。
# 大数竖式骨架:定位 i+j/i+j+1,先累加再拆进位res = [0] * (len(A) + len(B)) # 1) 结果至多 m+n 位for i in range(len(A) - 1, -1, -1): # 从低位往高位 for j in range(len(B) - 1, -1, -1): total = digit(A, i) * digit(B, j) + res[i + j + 1] res[i + j + 1] = total % 10 # 2) 个位留在 i+j+1 res[i + j] += total // 10 # 3) 进位送到 i+jreturn strip_leading_zero(res) # 4) 去前导 0,但别删光易错点
面试追问把动画讲成自己的话
追问为什么结果数组长度是 m+n?
追问i+j / i+j+1 这个下标怎么来的?
追问能不能不开 m+n 的中间数组、边乘边维护进位?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
检测正方形
LeetCode 2013 · 中等 · 沿着 数学 & 几何 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题