LeeCode_394. 字符串解码(栈+递归)

本文解析LeetCode题目#1267 - 解码字符串,介绍了使用字符栈、字符串栈和递归的方法来处理编码规则,通过实例演示了如何实现解码过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、介绍

1.题目描述

题目链接:https://leetcode-cn.com/problems/decode-string/

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a2[4] 的输入。

2.测试样例

"3[a]2[bc]"  
# "aaabcbc"

"3[a2[c]]"
# "accaccacc"

"2[abc]3[cd]ef"
# "abcabccdcdcdef"

"abc3[cd]xyz"
# "abccdcdcdxyz"

"3[z]2[2[y]pq4[2[jk]e1[f]]]ef"
# "zzzyypqjkjkefjkjkefjkjkefjkjkefyypqjkjkefjkjkefjkjkefjkjkefef"

二、题解

1、字符栈🟡

在这道题中,涉及到括号匹配,想到栈,定义两个栈,一个n_stk记录数字,一个c_stk记录字符串。

  • 对于数字:由于数字可能>10,因此遇到数字要*10+x储存,当遇到左括号后推入栈并重置为0
  • 对于左括号:遇到左括号,将当前数字和答案推入栈,并分别重置。因为遇到左括号说明后面有新的重复字符串,因此将前面的字符串暂存进栈
  • 对于字符:加入到当前答案中
  • 对于右括号:取出前面的字符串,将当前字符串循环加入到答案中,循环次数为n_stk的栈顶

以3[a2[c]]为例。num=0,ans=""

  1. 遇到3,num=3
  2. 遇到左括号,数字3入栈,重置num=0。ans"“入栈,重置ans=”"
  3. 遇到a,ans=‘a’
  4. 遇到2,num=2
  5. 遇到左括号,数字2入栈,重置num=0。ans"a"入栈,重置ans=""
  6. 遇到c,ans=‘c’
  7. 遇到右括号,取出字符串栈栈顶,赋给ans_temp=“a”;取出数字栈栈顶,赋给k=2;循环k 次,在ans_temp后面加入k个ans。完成后更新ans为ans_temp,即ans=acc
  8. 遇到右括号,取出字符串栈栈顶,赋给ans_temp="";取出数字栈栈顶,赋给k=3;循环k 次,在ans_temp后面加入k个ans。完成后更新ans为ans_temp,即ans=accaccacc

参考链接:https://leetcode-cn.com/problems/decode-string/solution/zi-fu-chuan-jie-ma-by-leetcode-solution/416067

class Solution {
public:
    string decodeString(string s) {
        // 数字栈和字符栈
        stack<int> n_stk;
        stack<string> c_stk;
        int num=0,i=0,k;
        int n=s.length();
        string ans="",ans_temp;
        while(i<n){
            // 重复次数
            if(s[i]>='0'&&s[i]<='9')num=num*10+(s[i]-'0');
            // 字符加入当前ans
            else if(s[i]>='a'&&s[i]<='z'){
                ans=ans+s[i];
            }
            // 遇左括号两边入栈,两边重置
            else if(s[i]=='['){
                n_stk.push(num);
                num=0;
                c_stk.push(ans);
                ans="";
            }
            // 遇右括号循环将当前字符串加入到前面的字符串
            else{
                ans_temp=c_stk.top();k=n_stk.top();
                while(k--) ans_temp=ans_temp+ans;
                ans=ans_temp;
                c_stk.pop();n_stk.pop();
            }
            i++;
        }
        return ans;
    }
};

image-20210916151937537

2、字符串栈🟡

除了处理字符,我们还可以将栈定义为存入字符串,其中,将单个字符s[i]转为字符串的方式为

string ss(1,s[i])
  • 若为左括号或字母,压入字符串栈c_stk
  • 若为右括号,弹出左括号前的所有字符,按序组合,重复k次,
  • 若为数字,压入数字栈n_stk

以e3[a2[c]]为例

  • 遇e,压入c_stk
  • 遇3,压入n_stk
  • 遇[,压入c_stk
  • 遇2,压入n_stk
  • 遇[,压入c_stk
  • 遇c,压入n_stk
  • 遇],弹出 c,重复2次,得cc。将cc压入c_stk
  • 遇],弹出并组合 cc、a,得到acc,重复3次,得accaccacc,将其压入c_stk
  • 遍历结束,弹出剩余元素并组合,得到eaccaccacc
class Solution {
public:
    string decodeString(string s) {
        stack<int> n_stk;
        stack<string> c_stk;
        int n=s.length();
        int i=0,k;
        string ans="",t="",temp="";
        while(i<n){
            string ss(1,s[i]);
            // 左括号或字母入栈
            if(ss=="["||(ss>="a"&&ss<="z")){
                c_stk.push(ss);
            }
            // 右括号
            else if(ss=="]"){
                // 弹出左括号前的所有字符并按序组合
                while(c_stk.top()!="["){
                    temp=c_stk.top();
                    c_stk.pop();
                    t=temp+t;
                }
                temp=t;
                // 弹出左括号
                c_stk.pop();
                // 该串重复k次
                int k=n_stk.top();
                n_stk.pop();
                for(int i=1;i<k;i++) t=t+temp;
                // 处理完入栈
                c_stk.push(t);
                t="";
            }
            // 若为数字
            else{
                n_stk.push(getnum(s,i));
            }
            i++;
        }
        // 组合整个字符串
        while(!c_stk.empty()){
            temp=c_stk.top();
            c_stk.pop();
            t=temp+t;
        }
        return t;
    }
    // 次数计算,可能有多位
    int getnum(string s,int &x){
        int ans=0;
        while(s[x]>='0'&&s[x]<='9'){
            ans=ans*10+(s[x]-'0');
            x++;
        }
        x--;
        return ans;
    }
};

image-20210918230612391

3、递归🟡

对于该问题,每当遇到左括号,剩余的内容可以当做一个新的字符串处理。因此想到递归算法。

  • 对于数字:由于数字可能>10,因此遇到数字要*10+x储存
  • 对于左括号:遇到左括号,右移一个字符,递归处理左括号后面的字符
  • 对于字符:加入到当前答案中
  • 对于右括号:返回当前答案

以3[a2[c]]为例。第一层num1=0,第一层ans1=""

  1. 遇到3,第一层num1=3
  2. 遇到左括号,指针i右移后调用递归,即接下来处理a2[c]]
  3. 遇到a,第二层ans2=“a”
  4. 遇到2,第二层num2=2
  5. 遇到左括号,指针i右移后调用递归,即接下来处理c]]
  6. 遇到c,第三层ans3=“c”
  7. 遇到右括号,返回第三层ans3"c"为第二层的temp。在第二层的ans2后面加上num2个temp。即得到返回的temp=“c”,原ans2=“a”,加上2个temp后 ans2=“acc”。
  8. 遇到右括号,返回第二层ans2"acc"为第一层的temp。在第一层的ans1后面加上num1个temp。即得到返回的temp=“acc”,原ans1="",加上3个temp后 ans1=“accaccacc”。
  9. 循环结束,返回ans1

参考链接:https://leetcode-cn.com/problems/decode-string/solution/decode-string-fu-zhu-zhan-fa-di-gui-fa-by-jyd/

class Solution {
public:
    string src; 
    int n,i;

    string getString() {
        // 仅代表该层的ans和num
        string ans="";
        int num=0;
        while(i<n){
            // 记录数字
            if(src[i]>='0'&&src[i]<='9') num=num*10+(src[i]-'0');
            else if(src[i]=='['){
                i++;
                // 进入下一层递归
                string temp=getString();
                // while(num--) ans=ans+temp;
                for(int j=0;j<num;j++) ans=ans+temp;
                num=0;
            }
            // 返回
            else if(src[i]==']') return ans;
            else ans+=src[i];
            i++;
        }
        return ans;
    }

    string decodeString(string s) {
        src = s;
        n=src.length();
        i = 0;
        return getString();
    }
};

image-20210916162333678

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值