leetcode 394. 字符串解码

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个状态:
分别是:

  1. 没有进入到模式中的字母串
  2. 进入到模式前缀的字母串
  3. 进入到模式后缀的字母串
  4. 数字串
  5. [
  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 :

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值