题目相关
题目链接
LeetCode中国,https://leetcode-cn.com/problems/decode-string/。注意需要登录。
题目描述
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string]
,表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a
或 2[4]
的输入。
示例
s = "3[a]2[bc]", 返回 "aaabcbc".
s = "3[a2[c]]", 返回 "accaccacc".
s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".
题目分析
LeetCode 给出本题难度中等。
题意分析
按照要求对输入字符串进行解码。
样例数据分析
样例数据 1
输入 3[a]2[bc],根据题目意思,我们知道第一个数字 3 表示后面中挎号内的字符串(也就是 a)要重复 3 次。第二个数字 2 表示后面中挎号内的字符串(也就是 bc)要重复 2 次。
因此样例输出 1 的输出为 aaabcbc。
样例数据 2
输入 3[a2[c]],根据题目意思,我们知道第一个数字 3 表示后面中挎号内的字符串(也就是 a2[c])要重复 3 次。第二个数字 2 表示后面中挎号内的字符串(也就是 c)要重复 2 次。
因此我们需要先重复 2[c],得到 cc,然后再重复 3[acc]。得到最后的输出为 accacc。
算法思路
从上面对样例数据 2 的分析中,我们可以发现最好的办法是使用递归。算法的大致描述如下:
1、当前的一个字符进行分析。我们知道这个字符只有两个可能,数字或者字母(题目没说保证小写字母,所以有可能会有大写字母)。
2、如果该字符是数字(使用 isdigit() 判断)。找出从这个位置开始的所有数字,比如 235[a],我们要找到 235。
3、下一位字符必然是 [ 符号,我们要找到最后一个 ]。怎么找?一个个看,如果是 [ 则记号变量加一,如果是 ] 则记号变量减一。
4、这样我们获得数字后面对应 [a[a]b[c]...x] 这个的开始位置和终止位置。然后递归解码从开始位置开始到终止位置结束的子字符串。
5、递归结束后,将找到的子字符串重复上面找到的数字次数。将这个新的字符加入到答案中。
6、如果改字符是字母。将该字符加入到答案中。
看上去确实有些拗口。下面我们可以结合一下代码解释。
AC 参考代码
class Solution {
public:
string decodeString(string s) {
string ans;//结果
//注意 for 循环的第三个参数没有。因为中间要不停修改
for (int i=0; i<s.length(); ) {
//解析每一个字符
if (true==isdigit(s[i])) {
//数字
//获取数字
int val = 0;
while (true==isdigit(s[i])) {
val = val*10+s[i]-'0';
i++;
}
//定位字母的开始和结束位置
int j=i+1;
int sum = 1;//下面至少有一个[
//确定有几个[],要考虑到3[a2[c]]这样用例
while (sum>0) {
if ('['==s[j]) {
sum++;
}
if (']'==s[j]) {
sum--;
}
j++;
}
//递归解决[i, j]内部的字符串
string ret = decodeString(s.substr(i+1, j-i-2));
//构造字符串
while (val--) {
ans += ret;
}
//更新 i 的位置
i = j;
} else {
//不是数字
ans += s[i++];
}
}
return ans;
}
};
假的吧。效率有这么高?我自己都不信。
P.S.
本题可以使用模拟来写,就是利用堆栈。