【力扣】394. 字符串解码 <递归、栈>

【力扣】394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。

示例 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”

提示:
1 <= s.length <= 30
s 由小写英文字母、数字和方括号 ‘[]’ 组成
s 保证是一个有效的输入。
s 中所有整数的取值范围为 [1, 300]

题解

类比 【卡码网】30. 字符串解压缩 <模拟、递归>
分别记录 数字,[,] 各出现的位置,进行递归解码。

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();

        System.out.print(decode(str));
    }

    public static String decode(String s) {
        int i = 0;
        int x = -1, y = -1, z = -1;

        // 记录 num[] 的位置,每次总是会找到最内层的三个
        // 若未找到说明已经完全解压缩,直接返回s
        while (i < s.length()) {
            if (s.charAt(i) == '[') {
                y = i;
            } else if (s.charAt(i) == ']') {
                z = i;
                break;
            }
            i++;
        }

        // 判断是否全部找到
        if (y != -1 && z != -1) {
            // 取出重复次数
            String str = s.substring(0, y);
            Pattern pattern = java.util.regex.Pattern.compile("\\d+$"); //\\d 匹配的是任何数字,等价于 [0-9]
            Matcher matcher = pattern.matcher(str);
            int times = 0;
            if (matcher.find()) {
                //System.out.println(matcher.group());
                times = Integer.parseInt(matcher.group());
            }

            //System.out.println(times);
            x = matcher.group().length();

            // 取出需重复子串
            String subString = s.substring(y + 1, z);

            StringBuilder decodeSubStringBuilder = new StringBuilder();
            for (int j = 0; j < times; j++) {
                decodeSubStringBuilder.append(subString);
            }

            //前段未处理的部分 + 与重复的部分 + 后段未处理的部分
            String decodeStr = s.substring(0, y - x) + decodeSubStringBuilder.toString() + s.substring(z + 1);
            //递归地对新构建的解码字符串进行解码,直到没有重复字符串信息为止
            return decode(decodeStr);
        }
        return s;
    }
}

双栈法:利用栈的思想

import java.lang.*;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.nextLine();

        System.out.print(decodeString(str));
    }
    
    public static String decodeString(String s) {
        //数字栈,数字栈保存需要在前缀重复的次数
        LinkedList<Integer> numStack = new LinkedList();
        //字符串栈,字符栈保存需要在前缀加上的字符串
        LinkedList<String> strStack = new LinkedList();
        //记录需重复的字符串
        StringBuilder subString = new StringBuilder();

        int num = 0;
        //遍历字符串
        for (int i = 0; i < s.length(); i++) {
            //当前字符
            char c = s.charAt(i);

            //当前字符是数字
            if (c >= '0' && c <= '9') {
                //计算num
                num = num * 10 + c - '0';
            }
            //当前字符是字母
            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
                subString.append(c);
            }
            //当前字符是左括号
            if (c == '[') {
                //数字入栈
                numStack.push(num);
                //字符串入栈
                strStack.push(subString.toString());

                //重置数字和临时字符串
                subString = new StringBuilder();
                num = 0;
            }

            //当前字符是右括号
            if (c==']'){
                StringBuilder preSubString = new StringBuilder().append(strStack.pop());
                int times = numStack.pop();

                for (int j = 0; j < times; j++) {
                    preSubString.append(subString);
                }
                subString = preSubString;
            }
        }

        return subString.toString();
    }
}
    /**
     * 利用2个栈,一个数字栈 numStack,一个字符串栈 strStack
     * 遍历字符串
     * 1、字符为数字,解析数字(注意连续数字的情况)存入 num
     * 2、字符为字母,拼接字母 存入 subString
     * 3、字符为左括号,把之前得到的数字 num 和 字符串 subString 分别压栈,然后把数字 num 重置为0,字符串 subString 重置为空串
     * 4、字符为右括号,数字栈栈顶数字出栈,作为重复次数 times,字符串栈栈顶字符串出栈,作为前缀字符串去拼接 subString 字母变量,总共拼接 times 次,拼接后的新字母串给 subString
     *
     * 例如:
     * 2[abc]3[cd]ef
     *  ↑
     * 遇到左括号,把数字 num=2 和 字符串 subString="" 入栈,并且 num 和 subString 重置
     *    |   |      |    |
     *    |   |      |    |
     *    |_2_|      |_""_|
     *   numStack    strStack
     *
     * 2[abc]3[cd]ef
     *      ↑
     * 遇到右括号,num=0 subString="abc",numStack 和 strStack 栈顶元素出栈 subString = strStack.pop() + subString * numStack.pop() = "" + "abc" * 2 =  "abcabc"
     *    |   |      |   |
     *    |   |      |   |
     *    |___|      |___|
     *   numStack    strStack
     *
     * 2[abc]3[cd]ef
     *        ↑
     * 遇到左括号,数字 num=3 和 字母 subString="abcabc" 入栈,并且 num 和 subString 重置
     *    |   |      |        |
     *    |   |      |        |
     *    |_3_|      |_abcabc_|
     *   numStack    strStack
     *
     * 2[abc]3[cd]ef
     *           ↑
     * 遇到右括号,num=0 subString= cd,numStack 和 strStack 栈顶元素出栈 subString = "abcabc" + "cd" * 3 = "abcabccdcdcd"
     *    |   |      |        |
     *    |   |      |        |
     *    |_3_|      |_abcabc_|
     *   numStack    strStack
     *
     * 遍历结束,最终结果 str="abcabccdcdcdef"
     */

你可能感兴趣的:(力扣及OJ,#,栈,队列,单调栈,#,模拟,leetcode,python,算法)