leetcode 394. 字符串解码
输入:s = “3[a2[c]]”
输出:“accaccacc”
class Solution {
public:
string decodeString(string s) {
int len = s.length();
if(len <= 0) {
return "";
}
stack<int> numbers; // 存储数字
stack<string> repeatAlpha; // 存储重复字符串,如果遇到3[2[yy]这种的,判断3[时要放#进去
int curIndex = 0; // 用while推进字符串的遍历
string res; // 最终结果
bool needProcess = false; // 是否处于 [] 中间
int j; // 临时变量
while(curIndex < len) {
if(s[curIndex] >= 'a' && s[curIndex] <= 'z' && needProcess == false) {
// 目前为止没有遇到 [ ,则直接追加到 res 后面
// res += s[curIndex];
res.append(1, s[curIndex]); // 追加1个重复字符
curIndex++;
} else if (s[curIndex] >= '0' && s[curIndex] <= '9') {
// 遇到了数字,代表立马进入[]模式,将数字存储到栈中
j = curIndex + 1;
while(j < len) {
if (s[j] >= '0' && s[j] <= '9') {
j++;
} else {
break;
}
}
numbers.push(atoi((s.substr(curIndex, j - curIndex)).c_str()));
curIndex = j;
} else if(s[curIndex] >= 'a' && s[curIndex] <= 'z' && needProcess == true && repeatAlpha.size() != numbers.size()) {
// 这段字符串处于[]期间,同时也是模式的前缀
// 比如:3[yy2[zz]]
// eg:
// 遍历到yy段前:
// numbers : 3
// repeatAlpha :
// 遍历到yy段时:
// numbers : 3
// repeatAlpha : yy
// 遍历到yy段前时,numbers栈比repeatAlpha栈大一个
// 遍历完yy段之后,numbers栈和repeatAlpha栈相同大小
j = curIndex + 1;
while(j < len) {
if (s[j] >= 'a' && s[j] <= 'z') {
j++;
} else {
break;
}
}
repeatAlpha.push(s.substr(curIndex, j - curIndex));
curIndex = j;
} else if(s[curIndex] >= 'a' && s[curIndex] <= 'z' && needProcess == true && repeatAlpha.size() == numbers.size()) {
// 这段字符串处于[]期间,同时也是模式的后缀
// 比如:2[3[yy]zz] ,当遍历到zz这段时,此时 repeatAlpha 栈和 numbers 栈大小相同
// 代表要重新改写 repeatAlpha栈的顶部元素
// eg:
// 遍历到yy段时:
// numbers : 2 3
// repeatAlpha : # yy
// 遍历到]段时:
// numbers : 2
// repeatAlpha : yyyyyy
// 再遍历到 zz段时
// 不能再往 repeatAlpha 栈中扔 zz 进去,而是要将 zz 附加到 yyyyyy 的后面
j = curIndex + 1;
while(j < len) {
if (s[j] >= 'a' && s[j] <= 'z') {
j++;
} else {
break;
}
}
string prevAlpha = repeatAlpha.top();
repeatAlpha.pop();
prevAlpha.append(s.substr(curIndex, j - curIndex));
repeatAlpha.push(prevAlpha);
curIndex = j;
} else if (s[curIndex] == '[') {
// 开启模式匹配
needProcess = true;
// 同时还要问下[之后是不是携带字母
// 比如:3[2[z]] ,遍历到第一个[时,并没有携带字母,而是携带子模式串
// 这种情况,就需要将 # 放入 repeatAlpha栈,以表示此次的循环字符串依赖于子串
// 等子串确定后之后,再来确定当前循环串
// 下一个不是重复字母
if(curIndex + 1 < len && (s[curIndex + 1] > 'z' || s[curIndex + 1] < 'a')) {
repeatAlpha.push("#");
}
curIndex++;
} else if (s[curIndex] == ']') {
// 代表一个模式匹配完成
string stmp = repeatAlpha.top();
repeatAlpha.pop();
int times = numbers.top();
numbers.pop();
if(!repeatAlpha.empty()) {
// 当前模式不是最外部的模式
string stmp1 = repeatAlpha.top();
repeatAlpha.pop();
if(stmp1 == "#") {
stmp1 = "";
}
for (j = 0; j < times; j++) {
stmp1.append(stmp);
}
repeatAlpha.push(stmp1);
} else {
// 当前模式是最外部的模式
for (j = 0; j < times; j++) {
res.append(stmp);
}
// 设置它不进入模式
needProcess = false;
}
curIndex++;
} else {
break;
}
}
return res;
}
};
3[z]2[2[y]pq4[2[jk]e1[f]]]ef
思路大概就是:
从左往右遍历字符串,用的是 curIndex++ 和 while 的方式,用于将一串字符串按段来遍历,而不是逐位遍历
状态机有6个状态:
分别是:
- 没有进入到模式中的字母串
- 进入到模式前缀的字母串
- 进入到模式后缀的字母串
- 数字串
- [
- ]
用双栈的方式来组织状态机中的数据
eg:
3[z]
遍历到4类型的数据:3
res :
numbers : 3
repeatAlpha :
遍历到5类型的数据:[
res :
numbers : 3
repeatAlpha :
遍历到2类型的数据:z
res :
numbers : 3
repeatAlpha : z
遍历到6类型的数据:]
res : zzz
numbers :
repeatAlpha :
遍历到6类型的数据:]
res : zzz
numbers :
repeatAlpha :
eg:
2[3[y]pq]
遍历到4类型的数据:2
res :
numbers : 2
repeatAlpha :
遍历到5类型的数据:[
res :
numbers : 2
repeatAlpha : # (提前探测了下一个字符是否是前缀字符串)
遍历到4类型的数据:
res :
numbers : 2 3
repeatAlpha : #
遍历到2类型的数据:
res :
numbers : 2 3
repeatAlpha : # y
遍历到6类型的数据:]
res :
numbers : 2
repeatAlpha : yyy
遍历到3类型的数据:pq
res :
numbers : 2
repeatAlpha : yyypq
遍历到6类型的数据:]
res : yyypqyyypq
numbers :
repeatAlpha :