LeetCode 43中等字符串
字符串相乘 图解题解
这道题到底在问什么
输入两个非负整数字符串 num1、num2(可能很大,超出 long 范围,不能转成整数),返回它们乘积的字符串。
- 输入
- num1="123", num2="456"
- 输出
- "56088"
最优解:一步一步想明白
- 3记住这条「i 位 × j 位 → 落在 i+j+1,进位进 i+j」。下面每一帧都在套它,看一遍就懂为什么是这两个位置。
- 4先准备一个长度 6 的格子(全 0)当草稿纸。它从左到右就是乘积从高位到低位每一位的暂存值,相乘的结果会一笔笔加进去。
- 53 乘 6 得 18。为什么加到第 5 位?因为 num1 第 2 位、num2 第 2 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 5;满十的进位往左一格、放到下标 4。
- 6把 18 加进第 5 位:它原来是 0,相加得 18。本位只能放个位 8,多出来的 1 进位到左边第 4 位(变成 1)。这一格的值就这样被更新了。
- 73 乘 5 得 15。为什么加到第 4 位?因为 num1 第 2 位、num2 第 1 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 4;满十的进位往左一格、放到下标 3。
- 8把 15 加进第 4 位:它原来是 1,相加得 16。本位只能放个位 6,多出来的 1 进位到左边第 3 位(变成 1)。这一格的值就这样被更新了。
- 93 乘 4 得 12。为什么加到第 3 位?因为 num1 第 2 位、num2 第 0 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 3;满十的进位往左一格、放到下标 2。
- 10把 12 加进第 3 位:它原来是 1,相加得 13。本位只能放个位 3,多出来的 1 进位到左边第 2 位(变成 1)。这一格的值就这样被更新了。
- 112 乘 6 得 12。为什么加到第 4 位?因为 num1 第 1 位、num2 第 2 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 4;满十的进位往左一格、放到下标 3。
- 12把 12 加进第 4 位:它原来是 6,相加得 18。本位只能放个位 8,多出来的 1 进位到左边第 3 位(变成 4)。这一格的值就这样被更新了。
- 132 乘 5 得 10。为什么加到第 3 位?因为 num1 第 1 位、num2 第 1 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 3;满十的进位往左一格、放到下标 2。
- 14把 10 加进第 3 位:它原来是 4,相加得 14。本位只能放个位 4,多出来的 1 进位到左边第 2 位(变成 2)。这一格的值就这样被更新了。
- 152 乘 4 得 8。为什么加到第 2 位?因为 num1 第 1 位、num2 第 0 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 2;满十的进位往左一格、放到下标 1。
- 16把 8 加进第 2 位:它原来是 2,相加得 10。本位只能放个位 0,多出来的 1 进位到左边第 1 位(变成 1)。这一格的值就这样被更新了。
- 171 乘 6 得 6。为什么加到第 3 位?因为 num1 第 0 位、num2 第 2 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 3;满十的进位往左一格、放到下标 2。
- 18把 6 加进第 3 位:它原来是 4,相加得 10。本位只能放个位 0,多出来的 1 进位到左边第 2 位(变成 1)。这一格的值就这样被更新了。
- 191 乘 5 得 5。为什么加到第 2 位?因为 num1 第 0 位、num2 第 1 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 2;满十的进位往左一格、放到下标 1。
- 20把 5 加进第 2 位:它原来是 1,相加得 6。本位只能放个位 6,多出来的 0 进位到左边第 1 位(变成 1)。这一格的值就这样被更新了。
- 211 乘 4 得 4。为什么加到第 1 位?因为 num1 第 0 位、num2 第 0 位的权重相乘,正好对应结果从右数的那一位,也就是数组下标 i+j+1 = 1;满十的进位往左一格、放到下标 0。
- 22把 4 加进第 1 位:它原来是 1,相加得 5。本位只能放个位 5,多出来的 0 进位到左边第 0 位(变成 0)。这一格的值就这样被更新了。
- 239 对数字(3×3)两两相乘、逐步进位,全部加完后草稿纸定格成 [0, 5, 6, 0, 8, 8]。因为每一步都做了「本位留个位、进位进左边」,所以现在每个格子都已经是 0~9 的单个数字了。
- 24把格子从左到右连起来是 "056088",最高位是 0(因为乘积没占满 6 位),去掉这个前导 0 得到最终答案 "56088"。绿框就是真正保留下来的那几位。
⚠️ 容易写错的地方
✗ 错:直接把字符串转成 int/long 相乘
✓ 对:用结果数组逐位模拟
题目数可能远超任何内置整数范围,转换即溢出
✗ 错:落位下标记成 i+j
✓ 对:个位落 i+j+1、进位落 i+j
记错一位整条结果全错,是本题最常见 bug
✗ 错:忘记去前导 0
✓ 对:拼完后 lstrip("0"),并对全 0 特判返回 "0"
乘积没占满 m+n 位时最高位是 0,不去掉答案就多一位
完整代码(Python / C++ / Java)
Python
def multiply(num1, num2):
if num1 == "0" or num2 == "0":
return "0"
m, n = len(num1), len(num2)
res = [0] * (m + n) # 结果至多 m+n 位
for i in range(m - 1, -1, -1):
for j in range(n - 1, -1, -1):
mul = (ord(num1[i])-48) * (ord(num2[j])-48)
s = mul + res[i + j + 1] # 加上该位已有值
res[i + j + 1] = s % 10 # 本位留个位
res[i + j] += s // 10 # 进位进左一位
return "".join(map(str, res)).lstrip("0") or "0"C++
string multiply(string num1, string num2) {
if (num1 == "0" || num2 == "0") return "0";
int m = num1.size(), n = num2.size();
vector<int> res(m + n, 0);
for (int i = m - 1; i >= 0; --i)
for (int j = n - 1; j >= 0; --j) {
int mul = (num1[i]-'0') * (num2[j]-'0');
int s = mul + res[i + j + 1];
res[i + j + 1] = s % 10;
res[i + j] += s / 10;
}
string out;
for (int d : res) if (!(out.empty() && d == 0)) out += ('0' + d);
return out.empty() ? "0" : out;
}Java
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) return "0";
int m = num1.length(), n = num2.length();
int[] res = new int[m + n]; // 结果至多 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 s = mul + res[i + j + 1]; // 加上该位已有值
res[i + j + 1] = s % 10; // 本位留个位
res[i + j] += s / 10; // 进位进左一位
}
}
StringBuilder sb = new StringBuilder();
for (int d : res) if (!(sb.length() == 0 && d == 0)) sb.append(d);
return sb.length() == 0 ? "0" : sb.toString();
}复杂度
时间
O(m·n)
num1 每位都要乘 num2 每位,双重循环 m×n 次
空间
O(m+n)
一个长度 m+n 的结果数组
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 字符串相乘 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么结果数组长度取 m+n 就一定够?+
m 位数最大约 10^m,n 位数最大约 10^n,乘积小于 10^(m+n),即至多 m+n 位,所以长度 m+n 一定装得下;多出的高位会是 0,最后去前导 0。
能不能不开数组、直接用字符串逐位拼?+
可以,但进位处理会很啰嗦、容易错。用整型数组当草稿、先把所有乘积加进去、最后统一成字符串,是最清晰的写法。
每步都 %10 落位,最后还需要再统一处理进位吗?+
不需要。因为每一对相乘时就把「本位留个位、进位进左一格」做掉了,乘完后每位天然 < 10,直接拼字符串即可。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 字符串相乘 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。