LeetCode-394. 字符串解码
问题描述
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数k,例如不会出现像 3a 或 2[4] 的输入。
测试用例保证输出的长度不会超过 10^5。
测试用例
示例 1:
输入:s = "3[a]2[bc]"
输出:"aaabcbc"
示例 2:
输入:s = "3[a2[c]]"
输出:"accaccacc"
示例 3:
输入:s = "2[abc]3[cd]ef"
输出:"abcabccdcdcdef"
示例 4:
输入:s = "abc3[cd]xyz"
输出:"abccdcdcdxyz"
解题思路
一开始看到题目的测试用例其实第一反应就是递归 因为考虑到是先要读取到括号中的内容然后再回溯通过前面的数字进行累加 并且测试用例2中出现了层级嵌套 因此天然就是递归的结构 ,那思路就很明了了 使用StringBuilder对下一层递归的返回值进行累加即可。
不过我一开始做的时候有点碰壁 因为我将index作为参数进行传递 导致dfs 中递归调用处理括号内部逻辑时,外层的index并没有随着内层的执行而向后移动。导致内层处理完了,外层又从老位置开始,或者根本不知道跳到哪里。
代码如下
java
class Solution {
/**
* 最初的版本
* 错误记录点:
* 1. 指针传递问题:index 是按值传递的,dfs 递归回来后父层的 index 没有更新,导致死循环或解析错误。
* 2. 逻辑覆盖不全:只处理了"前导字母 + 一组数字括号",无法处理"abc3[a]2[b]"这种并列多组的情况。处理完3[a]就停止了
* 3. 递归出口不全。
*/
public String decodeString(String s) {
return dfs(s, 0);
}
public String dfs(String s, int index) {
StringBuilder sbu = new StringBuilder();
// 1. 先读取前面的字母
while (index < s.length() && isChar(s.charAt(index))) {
sbu.append(s.charAt(index++));
}
// 2. 判断是否结束
if (index == s.length() || s.charAt(index) == ']') {
return sbu.toString();
}
// 3. 处理数字和括号
if (isNumber(s.charAt(index))) {
StringBuilder n = new StringBuilder();
// 读取数字
while (s.charAt(index) != '[') {
n.append(s.charAt(index++));
}
// 递归调用(问题:这里的 index+1 结果没有反馈给当前层的 index)
String plus = dfs(s, index + 1);
int times = Integer.parseInt(n.toString());
while (times > 0) {
sbu.append(plus);
times--;
}
}
// 错误点:执行完上面逻辑就直接返回了,如果字符串后面还有内容(如 "3[a]bc" 中的 bc)会被丢弃
return sbu.toString();
}
public boolean isNumber(char ch) {
return ch >= '0' && ch <= '9';
}
public boolean isChar(char ch) {
return ch >= 'a' && ch <= 'z';
}
}
正解
使用一个全局的index 这样外层就可以知道遍历到哪了 使用while(index<s.length())作为出口条件即可
代码如下
java
class Solution {
// 使用全局变量 index,确保在递归调用过程中,所有层级共享同一个遍历进度
int index = 0;
public String decodeString(String s) {
// ans 用于存储当前递归层级解析出来的字符串
StringBuilder ans = new StringBuilder();
// n 用于存储数字字符串(即括号前需要重复的次数)
StringBuilder n = new StringBuilder();
while (index < s.length()) {
char ch = s.charAt(index);
if (isChar(ch)) {
// 情况1:如果是普通字母,直接追加到当前层级的结果中
ans.append(ch);
index++;
}
else if (isNumber(ch)) {
// 情况2:如果是数字,累加到 n 中(处理多位数的情况,如 100[a])
n.append(ch);
index++;
}
else if (ch == '[') {
// 情况3:遇到左括号 '['
index++; // 跳过 '[',进入下一层递归
// 【核心】递归调用:去处理括号里面的内容,返回括号内解码后的字符串
String plus = decodeString(s);
// 将之前记录的数字字符串转为整数
int times = Integer.parseInt(n.toString());
// 根据倍数 times,将返回的子字符串重复追加到当前结果 ans 中
while (times > 0) {
ans.append(plus);
times--;
}
// 重复结束后,清空数字记录器 n,以便处理同级的下一个重复块
n.setLength(0);
}
else {
// 情况4:遇到右括号 ']'
index++; // 跳过 ']'
// 当前括号层级处理完毕,返回当前层级构造好的字符串
return ans.toString();
}
}
// 整个字符串遍历结束,返回最终结果
return ans.toString();
}
/**
* 判断字符是否为数字
*/
public boolean isNumber(char ch) {
return ch >= '0' && ch <= '9';
}
/**
* 判断字符是否为小写字母
*/
public boolean isChar(char ch) {
return ch >= 'a' && ch <= 'z';
}
}
时间复杂度:O(L)
L为结果字符串总长度
