这道 字符串解码 decodeString 的重点就是:用栈保存进入 [ 之前的状态,遇到 ] 再恢复状态并完成字符串展开。
代码总结
class Solution {
public:
string decodeString(string s) {
int time = 0; // 当前重复次数
string result = ""; // 当前层得到的字符串
stack<pair<int,string>> st; // 保存 <倍数, 上一层字符串>
for (auto c : s) {
// 1. 数字:计算重复次数,支持多位数
if (isdigit(c)) {
time = time * 10 + (c - '0');
}
// 2. 字母:加入当前字符串
if (isalpha(c)) {
result += c;
}
// 3. 遇到 '[':保存当前状态,进入下一层
if (c == '[') {
st.push({time, result});
time = 0;
result = "";
}
// 4. 遇到 ']':恢复上一层状态
else if (c == ']') {
auto [lasttime, laststr] = st.top();
st.pop();
// 当前字符串重复 lasttime 次
string temp = "";
for (int i = 0; i < lasttime; i++) {
temp += result;
}
// 与上一层字符串进行拼接
result = laststr + temp;
}
}
return result;
}
};
核心流程可以直接记成:
数字 → 计算 time
字母 → result += c
遇到 [
↓
把 {time, result} 压栈
↓
time = 0
result = ""
↓
开始处理括号内部
遇到 ]
↓
取出上一层 {lasttime, laststr}
↓
当前 result 重复 lasttime 次
↓
result = laststr + 重复后的字符串
例如:
3[a2[c]]
3[ → 保存 <3, "">
a2[ → 保存 <2, "a">
c] → "c" × 2 → "a" + "cc" = "acc"
] → "acc" × 3
最终:
"accaccacc"
你这次写代码出现的易错点
① time 一定初始化为 0
你最开始写过:
int time; // ❌
应该:
int time = 0; // ✅
因为后面马上使用:
time = time * 10 + (c - '0');
如果没有初始化,time 的初始值是不确定的。
② 多位数字不能只写 c - '0'
错误理解:
time = c - '0';
只能处理:
3[a]
不能正确处理:
12[a]
所以应该:
time = time * 10 + (c - '0');
例如:
读到 1:
0 × 10 + 1 = 1
读到 2:
1 × 10 + 2 = 12
记住这个常用公式:
num = num * 10 + 当前数字;
③ stack<pair<int,string>> 压入的是一个 pair
你之前写过:
st.push(time, result); // ❌
但栈的一个元素是:
pair<int,string>
所以应该:
st.push({time, result}); // ✅
也可以:
st.emplace(time, result); // ✅
④ result = "" 和 result = " " 不一样
你之前写过:
result = " "; // ❌
这是一个真正的空格字符。
应该:
result = ""; // ✅
区别:
"" → 空字符串
" " → 包含一个空格
⑤ 遇到 [ 后必须清空当前状态
st.push({time, result});
time = 0;
result = "";
因为:
st.push({time, result});
已经把上一层状态保存好了。
清空之后,time 和 result 才能专门处理括号里面的新一层。
可以理解成:
保存上一层
↓
清空
↓
处理下一层
↓
遇到 ]
↓
恢复上一层
⑥ st.top() 返回的是一个 pair
你之前写过类似:
auto lasttime, laststr = st.top(); // ❌
正确:
auto [lasttime, laststr] = st.top(); // ✅
这是 C++17 的结构化绑定。
如果栈顶:
<3, "abc">
那么:
auto [lasttime, laststr] = st.top();
相当于:
lasttime = 3
laststr = "abc"
也就是:
pair.first → lasttime
pair.second → laststr
⑦ ] 时使用的是 lasttime,不是 time
你之前这里写错过:
for (int i = 0; i < time; i++) { // ❌
temp += result;
}
应该:
for (int i = 0; i < lasttime; i++) { // ✅
temp += result;
}
因为遇到 [ 时:
st.push({time, result});
time = 0;
原来的倍数已经被保存到栈里了。
遇到 ]:
auto [lasttime, laststr] = st.top();
才把原来的倍数取回来。
最后把这题压缩成一句最值得记的:
数字算倍数,字母直接拼;
[保存现场并清空,]恢复现场并重复拼接。
时间复杂度主要取决于最终解码字符串的长度,可以理解为 O(n+L)O(n + L),其中 LL 是最终结果长度;栈空间复杂度与最大嵌套深度有关。