LeetCode 415简单字符串
字符串相加 图解题解
这道题到底在问什么
给两个用字符串表示的非负整数 num1、num2,不能直接转 int(可能超大),返回它们相加的和(也用字符串表示)。
- num1
- "456"
- num2
- "77"
- 输出
- "533"
最优解:一步一步想明白
- 3把两个数右对齐摆好,从最右边那一列开始往左加,每列算出「本位数字 + 是否进位」。下面就一列一列地演示。
- 4两个数不一样长怎么办?短的那个走完后,缺的位就当成 0 来加。下面这排格子是要填的结果,我们从右往左一格一格填进去。
- 5准备从最低位开始填这 4 个格子是结果的「位子」(最多 3 位,留 1 个给可能的进位)。下划线 _ 表示还没填。我们从最右边那一格开始。
- 6i→6, j→7指针落在最右格(个位)。num1 末位是 6,num2 末位是 7,加上进位 0。先把这一列的三个数找齐。
- 76 + 7 + 0 = 136+7=13,满 10 了!个位数字取 13 除以 10 的余数 3,进位取 13 除以 10 的商 1,留给下一列。
- 8结果末位 = 3,carry = 1把 3 填进最右格(变绿)。进位 1 记在心里。两个指针一起往左挪一位,处理十位。
- 9i→5, j→7指针移到十位格。num1 这位是 5,num2 这位是 7,别忘了还要加上上一列的进位 1。
- 105 + 7 + 1 = 135+7+1=13,又满 10。本位还是 3(13%10),又产生一个进位 1(13/10)。进位会像接力一样一直传下去。
- 11结果 = 33,carry = 1十位填 3(再变绿一格)。进位仍是 1。指针继续左移,处理百位。
- 12i→4, j 越界 → 当 0百位这里 num2 已经走完了(它只有两位)。这就是短的补 0:num2 这位当成 0 来加。
- 134 + 0 + 1 = 54+0+1=5,这次不满 10,本位就是 5,进位归 0。
- 14结果 = 533,carry = 0百位填 5。现在两个数都扫完、进位也归 0,加法结束。最左那格没用上(因为没多出进位)。
- 15倒序填的,正着读 = 533我们是从右往左填的,但读的时候从左往右正好就是 533。校验:456 + 77 = 533 ✓。最左空格变灰丢弃。
- 16结果槽清空,从个位起换一对不等长的数 11 + 123 再走一遍,专看「短的那个走完后补 0」。指针先落在个位。
- 171 + 3 + 0 = 4个位:1+3=4,不满 10。填 4,无进位。指针左移。
- 181 + 2 + 0 = 3十位:1+2=3。填 3。此时 num1(只有两位)走完了,但 num2 还有百位。
- 190 + 1 + 0 = 1百位:num1 已越界补 0,num2 是 1,得 1。11+123 = 134 ✓。不管谁短,缺的位补 0 就统一了。
- 20重点是那个 or carry:就算两个数都加完了,只要还剩一个进位(比如 99+1),也必须再多算一列把进位的 1 落下来。下面专门演示这个坑。
- 21结果槽清空换 99 + 1 看进位长出新位。结果槽留 3 格(2 位数 + 1 个进位位)。指针落在个位。
- 229 + 1 + 0 = 10个位:9+1=10,满 10。本位取余数 0,进位取商 1。
- 23个位填 0,carry = 1个位填 0(变绿),进位 1 带走。指针左移到十位。
- 249 + 0 + 1 = 10十位:num1 是 9,num2 补 0,加进位 1 = 10。又填 0,进位还是 1。此时两个数都走完了——但进位还在!
- 25carry 单独成一位因为有 or carry 条件,循环再走一次,把剩下的进位 1 填到最高位。99+1 = 100,正好多出一位。漏了 or carry 就会错成 "00"。
⚠️ 容易写错的地方
✗ 错:while 只判 i≥0 且 j≥0
✓ 对:条件要带上 or carry
如 99+1,两数加完后还剩进位 1,漏了就丢最高位、结果错成 00
✗ 错:直接 int(num1)+int(num2)
✓ 对:逐位字符相加
题目数可达几百位,远超 long,转数字直接溢出
✗ 错:忘了最后反转结果
✓ 对:res 反转再返回
我们从低位往高位 append,顺序是反的,正着输出会得到镜像数字
完整代码(Python / C++ / Java)
Python
class Solution:
def addStrings(self, num1, num2):
i, j = len(num1) - 1, len(num2) - 1
carry = 0
res = []
while i >= 0 or j >= 0 or carry:
x = ord(num1[i]) - ord('0') if i >= 0 else 0
y = ord(num2[j]) - ord('0') if j >= 0 else 0
s = x + y + carry
res.append(str(s % 10)) # 本位
carry = s // 10 # 进位
i -= 1
j -= 1
return ''.join(reversed(res))C++
class Solution {
public:
string addStrings(string num1, string num2) {
int i = num1.size() - 1, j = num2.size() - 1;
int carry = 0;
string res;
while (i >= 0 || j >= 0 || carry) {
int x = i >= 0 ? num1[i] - '0' : 0;
int y = j >= 0 ? num2[j] - '0' : 0;
int s = x + y + carry;
res += char('0' + s % 10); // 本位
carry = s / 10; // 进位
i--; j--;
}
reverse(res.begin(), res.end());
return res;
}
};Java
class Solution {
public String addStrings(String num1, String num2) {
int i = num1.length() - 1, j = num2.length() - 1;
int carry = 0;
StringBuilder res = new StringBuilder();
while (i >= 0 || j >= 0 || carry != 0) {
int x = i >= 0 ? num1.charAt(i) - '0' : 0;
int y = j >= 0 ? num2.charAt(j) - '0' : 0;
int s = x + y + carry;
res.append(s % 10); // 本位
carry = s / 10; // 进位
i--; j--;
}
return res.reverse().toString();
}
}复杂度
时间复杂度
O(max(m,n))
m、n 是两串长度;循环次数 = 较长那串的位数(最多再多 1 列给进位),每列常数操作
空间复杂度
O(max(m,n))
结果串长度约等于较长串(最多 +1),除结果外只用了 i/j/carry 几个变量
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 字符串相加 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么不能直接转成整数相加?+
题目说数字可能极长(几百位),远超 int/long 的范围,转换会溢出;所以只能按字符逐位模拟竖式。
两个数不一样长怎么处理?+
指针越界的那一位当成 0 来加,即 i<0 或 j<0 时取值为 0,逻辑统一。
如果要做字符串相乘(LC43)思路类似吗?+
类似,也是模拟竖式,但乘法要处理每位乘积错位累加,通常用一个长度 m+n 的数组记每个位置的贡献再统一处理进位。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 字符串相加 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。