394. Decode String (解码字符串)

本文介绍了解码特定规则编码字符串的方法,提供了递归和迭代两种实现方案,并详细解释了每种方法的工作原理。

Given an encoded string, return it’s decoded string.

The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times. Note that k is guaranteed to be a positive integer.

You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc.

Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there won’t be input like 3a or 2[4].

Examples:

s = "3[a]2[bc]", return "aaabcbc".
s = "3[a2[c]]", return "accaccacc".
s = "2[abc]3[cd]ef", return "abcabccdcdcdef".

这道题让我们把一个按一定规则编码后的字符串解码成其原来的模样,编码的方法很简单,就是把重复的字符串放在一个中括号里,把重复的次数放在中括号的前面,注意中括号里面有可能会嵌套中括号,这题可以用递归和迭代两种方法来解,我们首先来看递归的解法,我们把一个中括号中的所有内容看做一个整体,一次递归函数返回一对中括号中解码后的字符串。给定的编码字符串实际上只有四种字符,数字,字母,左中括号,和右中括号。那么我们开始用一个变量i从0开始遍历到字符串的末尾,由于左中括号都是跟在数字后面,所以我们首先遇到的字符只能是数字或者字母,如果是字母,我们直接存入结果中,如果是数字,我们循环读入所有的数字,并正确转换,那么下一位非数字的字符一定是左中括号,我们指针右移跳过左中括号,对之后的内容调用递归函数求解,注意我们循环的停止条件是遍历到末尾和遇到右中括号,由于递归调用的函数返回了子中括号里解码后的字符串,而我们之前把次数也已经求出来了,那么循环添加到结果中即可,参见代码如下:

class Solution {
public:
    string decodeString(string s) {
        int i = 0;
        return decode(s, i);
    }
    string decode(string s, int& i) {
        string res = "";
        int n = s.size();
        while (i < n && s[i] != ']') {
            if (s[i] < '0' || s[i] > '9') {
                res += s[i++];
            } else {
                int cnt = 0;
                while (i < n && s[i] >= '0' && s[i] <= '9') {
                    cnt = cnt * 10 + s[i++] - '0';
                }
                ++i;
                string t = decode(s, i);
                ++i;
                while (cnt-- > 0) {
                    res += t;
                }
            }
        }
        return res;
    }
};

我们也可以用迭代的方法写出来,当然需要用stack来辅助运算,我们用两个stack,一个用来保存个数,一个用来保存字符串,我们遍历输入字符串,如果遇到数字,我们更新计数变量cnt;如果遇到左中括号,我们把当前cnt压入数字栈中,把当前t压入字符串栈中;如果遇到右中括号时,我们取出数字栈中顶元素,存入变量k,然后给字符串栈的顶元素循环加上k个t字符串,然后取出顶元素存入字符串t中;如果遇到字母,我们直接加入字符串t中即可,参见代码如下:

class Solution {
public:
    string decodeString(string s) {
        string res = "", t = "";
        stack<int> s_num;
        stack<string> s_str;
        int cnt = 0;
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] >= '0' && s[i] <= '9') {
                cnt = 10 * cnt + s[i] - '0';
            } else if (s[i] == '[') {
                s_num.push(cnt);
                s_str.push(t);
                cnt = 0; t.clear();
            } else if (s[i] == ']') {
                int k = s_num.top(); s_num.pop();
                for (int j = 0; j < k; ++j) s_str.top() += t;
                t = s_str.top(); s_str.pop();
            } else {
                t += s[i];
            }
        }
        return s_str.empty() ? t : s_str.top(); //正常输入格式下,s_str是空的,可以直接输出t.
    }
};

笔记:call back,考察递归迭代两种编程方式,题目比较典型。

### 解法分析 LeetCode 394题要求实现字符串解码功能,输入格式为 `k[encoded_string]`,其中 `k` 是正整数,表示重复次数,`encoded_string` 是需要重复的内容。解码后返回重复 `k` 次的字符串。 该问题可以使用 **栈(Stack)** 来解决,主要思路是利用两个栈分别保存当前的数字和字符串状态。遍历输入字符串,遇到数字时保存到数字栈中,遇到字符时拼接到当前字符串,遇到 `[` 时保存当前字符串和数字到栈中,遇到 `]` 时从栈中取出数据进行解码拼接。 --- ### Java 解法实现 以下是一个清晰的实现方式,使用 `LinkedList` 作为栈结构来存储数字和字符串: ```java class Solution { public String decodeString(String s) { LinkedList<Integer> numStack = new LinkedList<>(); LinkedList<String> strStack = new LinkedList<>(); StringBuilder sb = new StringBuilder(); int num = 0; for (char c : s.toCharArray()) { if (Character.isDigit(c)) { num = num * 10 + (c - '0'); } else if (c == '[') { numStack.push(num); strStack.push(sb.toString()); sb = new StringBuilder(); num = 0; } else if (c == ']') { int repeat = numStack.pop(); String temp = sb.toString(); sb = new StringBuilder(); for (int i = 0; i < repeat; i++) { sb.append(temp); } sb.insert(0, strStack.pop()); } else { sb.append(c); } } return sb.toString(); } } ``` --- ### 示例输入与输出 以下是一些测试用例及输出结果: - 输入:`"3[a]2[bc]"` 输出:`"aaabcbc"` - 输入:`"3[a2[c]]"` 输出:`"accaccacc"` - 输入:`"2[abc]3[cd]ef"` 输出:`"abcabccdcdcdef"` 这些测试用例可以验证解码逻辑是否正确[^5]。 --- ### 算法解析 1. **初始化栈**:使用两个栈 `numStack` 和 `strStack` 分别保存当前数字和字符串状态。 2. **数字处理**:遇到数字字符时,将其转换为整数并保存。 3. **左括号处理**:遇到 `[` 时,将当前数字和字符串压入栈中,并重置当前字符串和数字。 4. **右括号处理**:遇到 `]` 时,取出栈顶的数字和字符串,进行解码拼接。 5. **字符处理**:遇到字母时,直接追加到当前字符串中。 --- ### 时间与空间复杂度 - **时间复杂度**:`O(n)`,其中 `n` 是输入字符串的长度。每个字符最多被处理一次。 - **空间复杂度**:`O(n)`,栈和字符串构建的空间开销。 --- ### 递归解法(可选) 除了栈结构,还可以使用递归方法实现字符串解码。递归的核心思想是每次遇到 `[` 时进入下一层递归,遇到 `]` 时返回当前层的结果。 ```java class Solution { private int ptr = 0; public String decodeString(String s) { StringBuilder sb = new StringBuilder(); int num = 0; while (ptr < s.length()) { char c = s.charAt(ptr); if (Character.isDigit(c)) { num = num * 10 + (c - '0'); } else if (c == '[') { ptr++; String decoded = decodeString(s); for (int i = 0; i < num; i++) { sb.append(decoded); } num = 0; } else if (c == ']') { ptr++; return sb.toString(); } else { sb.append(c); } ptr++; } return sb.toString(); } } ``` --- ### 总结 LeetCode 394题的核心在于字符串的嵌套解析,栈结构能够很好地保存当前状态,而递归方法则利用函数调用栈实现类似效果。两种方法都可以高效解决问题,选择哪种方式取决于个人编码习惯和性能需求。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值