字符串解码[括号匹配问题]

前言

对于括号匹配问题,典型的解法就算递归进行括号匹配,当然也可以栈模拟。在此基础上才能完成额外的操作,解答任何括号匹配问题。

一、字符串解码

在这里插入图片描述

二、括号匹配问题

1、栈模拟–从左到右

// 字符串解码
public class DecodeString {
    /*
    括号匹配问题,可以递归,也可栈模拟。
     */
    // 栈模拟
    /*
        栈中存stringbuilder。
        碰到‘[’时,入栈一个空stringbuilder;
        碰到‘]’,将栈顶的stringbuilderappend到上一个stringbuilder中;
        碰到普通字符时,将字符加入栈顶stringbuilder中。
        如果从前往后遍历,则需要用一个栈把'['前的数字存在栈中;如果从后往前遍历,则不用。
     */
    public String decodeString(String s) {
        // 申请存字符和倍数的栈
        Stack<StringBuilder> strSK = new Stack<>();
        Stack<Integer> intSK = new Stack<>();
        // 初始化两个栈
        strSK.push(new StringBuilder());
        intSK.push(1);
        // 遍历字符串
        while (idx < s.length()) {
            char ch = s.charAt(idx++);
            // 如果ch是'[',则idx++(上面统一idx++了!),将新stringbuilder入栈。
            if (ch == '[') {
                strSK.push(new StringBuilder());
            }
            // 如果ch是']',则idx++,将栈顶stringbuilder以一定倍数融入上一个stringbuilder中。
            else if (ch == ']') {
                // 以一定倍数融合。
                int size = intSK.pop();
                StringBuilder topSB = strSK.pop();
                StringBuilder peekSB = strSK.peek();
                for (int i = 0; i < size; i++) peekSB.append(topSB.toString());
            }
            // 如果是普通字符,则加入topSB即可。
            else if (Character.isLetter(ch)) strSK.peek().append(ch);
                // 如果是数字,则需要获取该数有多大,并加入倍数栈中。
            else {
                int n = getNum(s, ch - '0');

                intSK.push(n);
            }
        }
        return strSK.peek().toString();
    }

    int idx = 0;// 遍历字符串的下标。

    // 采用10倍扩容法来获取数字大小。
    private int getNum(String s, int num) {

        while (idx < s.length() && Character.isDigit(s.charAt(idx))) num = num * 10 + s.charAt(idx++) - '0';

        return num;
    }

}

2、栈模拟–从右到左

// 如果是倒序,就不用倍数栈了,每次拿到'['时,取后面的倍数即可,最后做一个翻转。
class DecodeString2 {
    /*
    括号匹配问题,可以递归,也可栈模拟。
     */
    // 栈模拟
    /*
        栈中存stringbuilder。
        碰到‘[’时,入栈一个空stringbuilder;
        碰到‘]’,将栈顶的stringbuilderappend到上一个stringbuilder中;
        碰到普通字符时,将字符加入栈顶stringbuilder中。
        如果从前往后遍历,则需要用一个栈把'['前的数字存在栈中;如果从后往前遍历,则不用。
     */
    public String decodeString(String s) {
        // 初始化全局变量。
        init(s);
        // 申请存字符和倍数的栈
        Stack<StringBuilder> strSK = new Stack<>();
        // 初始化两个栈
        strSK.push(new StringBuilder());
        // 遍历字符串
        while (idx >= 0) {
            // 获取字符,统一idx--;
            char ch = s.charAt(idx--);
            // 如果ch是']',将新stringbuilder入栈。
            if (ch == ']') strSK.push(new StringBuilder());
            // 如果ch是']',则idx--,将栈顶stringbuilder以一定倍数融入上一个stringbuilder中。
            if (ch == '[') {
                // 以一定倍数融合。
                int size = getNum();
                StringBuilder topSB = strSK.pop();
                StringBuilder peekSB = strSK.peek();
                for (int i = 0; i < size; i++) peekSB.append(topSB.toString());
            }
            // 如果是普通字符,则加入topSB即可。
            if (Character.isLetter(ch)) strSK.peek().append(ch);

        }
        return strSK.peek().reverse().toString();
    }

    // 初始化全局变量
    private void init(String s) {
        this.s = s;
        this.idx = s.length() - 1;
    }

    String s;
    int idx;// 遍历字符串的下标。

    // 采用10倍扩容法来获取数字大小。
    private int getNum() {
        int num = 0;
        int n = 1;

        while (idx >= 0 && Character.isDigit(s.charAt(idx))) {
            num += (s.charAt(idx--) - '0') * n;

            n *= 10;
        }

        return num;
    }
}

3、递归匹配

// 碰到'['则递归,并传入前面的参数。
class DecodeString3 {
    /*
    括号匹配问题,可以递归,也可栈模拟。
     */
    // 栈模拟
    /*
        栈中存stringbuilder。
        碰到‘[’时,入栈一个空stringbuilder;
        碰到‘]’,将栈顶的stringbuilderappend到上一个stringbuilder中;
        碰到普通字符时,将字符加入栈顶stringbuilder中。
        如果从前往后遍历,则需要用一个栈把'['前的数字存在栈中;如果从后往前遍历,则不用。
     */
    public String decodeString(String s) {
        // 初始化全局变量。
        init(s);
        // 递归解决。
        return dfs(1).toString();
    }

    public StringBuilder dfs(int size) {
        StringBuilder sb = new StringBuilder();

        int n = 1;
        while (idx < s.length() && s.charAt(idx) != ']') {
            char ch = s.charAt(idx++);
            // 碰到'[',递归得到StringBuilder对象,并融入该层sb.
            if (ch == '[') sb.append(dfs(n));
            // 碰到数字,得到数字,更新n值。
            if (Character.isDigit(ch)) n = getNum(ch - '0');
            // 碰到普通字符,自己append加入。
            if (Character.isLetter(ch)) sb.append(ch);
        }
        // 碰到']',或者访问完成了。
        ++idx;
        // 字符放大,并返回。
        StringBuilder rs = new StringBuilder();
        for (int i = 0; i < size; i++) rs.append(sb.toString());

        return rs;
    }

    // 初始化全局变量
    private void init(String s) {
        this.s = s;
    }

    String s;
    int idx = 0;// 遍历字符串的下标。

    // 采用10倍扩容法来获取数字大小。
    private int getNum(int num) {

        while (idx < s.length() && Character.isDigit(s.charAt(idx))) num = num * 10 + s.charAt(idx++) - '0';

        return num;
    }
}

总结

1)括号匹配问题,可递归匹配,也可栈模拟。对于栈模拟,需要知道栈里存储些什么。

2)一题多解,融合贯通,会发现不一样的bug,训练出严谨的逻辑,沉淀更多知识点。

参考文献

[1] LeetCode 字符串解码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值