LeetCode每日一题--394字符串解码

342 阅读3分钟

DailyChallenge

394. 字符串解码

20200528

难度:中等

题目描述

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

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

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

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

示例:

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

Solution

  • [x] 思路一:LinkedList模拟栈

    可能会涉及到括号里嵌套了括号的情况,用栈来完成。想到了这道题20. 有效的括号

  • 遇到数字,入栈(这里注意数字可能有多位,比如"100[leetcode]",是把这整个数字入栈)

  • 遇到左括号或者字母,入栈

  • 遇到右括号时,开始出栈,直到'['为止。出栈后的顺序和原来字符串里的反了,所以翻转一下。由于左括号前一定是数字(代表括号里子字符串的次数),将翻转后的序列根据次数拼接得到新的子字符串并入栈,这样一个 k[] 的子串就构建好了放在 stack 里

  • 原字符串遍历完成后,此时栈中的元素从底到顶遍历拼接,得到答案。

class Solution {
    public String decodeString(String s) {
        LinkedList<String> stack = new LinkedList<>();
        int i = 0;
        while(i < s.length()){
            char c = s.charAt(i);
            if(Character.isDigit(c)){
                //数字入栈,注意数字可能有多位,比如"100[leetcode]"
                String number = "";
                while(Character.isDigit(s.charAt(i))){
                    number += String.valueOf(s.charAt(i++));
                }
                stack.addLast(number);
            }else if(Character.isLetter(c) || c == '['){
                //字母或者左括号,入栈
                stack.addLast(String.valueOf(c));
                i++;
            }else{
                //到']'的时候,开始出栈,直到'[',左括号前一定是数字
                i++;
                List<String> list = new ArrayList<>();
                while(!"[".equals(stack.peekLast())){
                    list.add(stack.removeLast());
                }
                // 翻转顺序
                Collections.reverse(list);
                // 左括号出栈
                stack.removeLast();
                // 左括号前面试数字,代表里面出现的次数
                int count = Integer.parseInt(stack.removeLast());
                // String sub = String.join(",", list);
                // List to String
                String sub = "";
                for(String s_list : list){
                    sub += s_list;
                }
                String subsub = sub;
                while(count > 1){
                    sub += subsub;
                    count--;
                }
                //构造出来的字符串入栈
                stack.addLast(sub);
            }
        }
        // 从底往上遍历栈,返回答案
        String res = "";
        for(String s_stack : stack){
            res += s_stack;
        }
        return res;
    }
}

Tips:

  • LinkedList而不是Stack就是为了方便最后栈中的元素从底到顶遍历拼接

  • [ ] 思路二:递归

    [] 分别作为递归的开启与终止条件。

    • s[i] == ']'时,返回当前括号内记录的 res字符串与 ]的索引i(更新上层递归指针位置);
    • s[i] == '['时,开启新一层递归,记录此 [...]内字符串tmp和递归后的最新索引 i,并执行 res + multi * tmp 拼接字符串。
    • 遍历完毕后返回 res
    class Solution {
        public String decodeString(String s) {
            return dfs(s, 0)[0];
        }
        private String[] dfs(String s, int i) {
            StringBuilder res = new StringBuilder();
            int multi = 0;
            while(i < s.length()) {
                if(s.charAt(i) >= '0' && s.charAt(i) <= '9') 
                    multi = multi * 10 + Integer.parseInt(String.valueOf(s.charAt(i))); 
                else if(s.charAt(i) == '[') {
                    String[] tmp = dfs(s, i + 1);
                    i = Integer.parseInt(tmp[0]);
                    while(multi > 0) {
                        res.append(tmp[1]);
                        multi--;
                    }
                }
                else if(s.charAt(i) == ']') 
                    return new String[] { String.valueOf(i), res.toString() };
                else 
                    res.append(String.valueOf(s.charAt(i)));
                i++;
            }
            return new String[] { res.toString() };
        } 
    }
    

本文使用 mdnice 排版