LeetCode 394. 字符串解码(Java代码)

前往LeetCode做题

题目描述

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

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

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

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

输入输出样例

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

辅助栈

需要以下几个变量:

  • 乘数栈:存储3、11、2这样的乘数
  • 被乘字符串栈:存储每一阶段需要被乘的字符串
  • 乘数:暂存乘数
  • 当前字串:

循环遍历经过编码的字符串

  • 如果碰到 [ ,就将乘数入栈,同时将当前字串如栈
    入栈以后,将原来的变量或置0,或清空(重赋值)
  • 如果碰到 ],将栈中乘数弹出,用新变量存储
    将当前字串乘以操作数,再将栈顶弹出,和它连接
  • 如果碰到数字字符,可能会是连续的,如12,所以。。。
  • 如果碰到的是其它字符,一律让此字符与 当前字串拼接

代码:

class Solution {
    public String decodeString(String s) {
        // 存储乘数的栈
        Stack<Integer> stack_multi = new Stack<Integer>();
        // 存储被乘字符串的字符串
        Stack<String> stack_str = new Stack<String>();
        // 乘数
        int multi = 0;
        // 当前子串
        StringBuilder ret = new StringBuilder();

        // 开始遍历字符串
        for(Character c : s.toCharArray()){
            if(c == '['){
                // 将乘数入栈,并置0
                stack_multi.push(multi);
                multi = 0;
                // 将当前字串入栈,并重赋值
                stack_str.push(ret.toString());
                ret = new StringBuilder();
            }
            else if(c == ']'){
                // 乘数弹出,用新变量存储
                int cur_multi = stack_multi.pop();
                // 当前字串乘以乘数
                StringBuilder temp = new StringBuilder();
                for(int i=0; i<cur_multi; i++) temp.append(ret);
                // 将栈顶弹出,并和拼接好的字串连接
                ret = new StringBuilder(stack_str.pop()+temp);
            }
            else if(c >= '0' && c <= '9') multi = multi*10 + Integer.parseInt(c+"");
            else
                ret.append(c);
        }
        return ret.toString();
    }
}

递归法——使用全局变量

思路
[ 是开启递归的条件,此时需要存储 此刻的multi和ret
] 是结束递归的条件,此时直接返回即可。

以2[a3[bc]] 为例:
---------------------------
当前遍历		multi(乘数)		ret(当前字串)
   '2'		   0			    ""
   '[' 		----------开启递归----------		存储本地值:cur_multi(2)、cur_str("")
   置空		   0				""
   'a'		   0				"a"
   '3'		   3				"a"
   '[' 		----------开启递归----------		存储本地值:cur_multi(3)、cur_str("a")
    'b'		   0				"b"
    'c'		   0				"bc"
   ']' 		----------结束递归----------		使用本地值:cur_multi(3)、cur_str("a")
   使用本地值   0				"abcbcbc"
   ']' 		----------结束递归----------		使用本地值:cur_multi(2)、cur_str("")
   使用本地值   0				"abcbcbcabcbcbc"

递归的时候,我使用了全局变量,这个决定让我的编码变得简单了,可以直接将上面辅助栈的代码拿来用。

但是运行速度上还是有点不足的

代码:

class Solution {
    // 乘数
    int multi = 0;
    // 当前子串
    StringBuilder ret = new StringBuilder();
    // 索引
    int index = 0;
    public String decodeString(String s) {
        while(index < s.length()){
            char c = s.charAt(index++);
            if(c == '['){
                // 将乘数入栈,并置0
                int cur_multi = multi;
                multi = 0;
                // 将当前字串入栈,并重赋值
                String cur_str = ret.toString();
                ret = new StringBuilder();
                // 开启递归
                decodeString(s);
                // 递归返回之后
                
                // 乘数弹出,用新变量存储
                // ...
                // 当前字串乘以乘数
                StringBuilder temp = new StringBuilder();
                for(int i=0; i<cur_multi; i++) temp.append(ret);
                // 将栈顶弹出,并和拼接好的字串连接
                ret = new StringBuilder(cur_str+temp);
            }
            else if(c == ']'){
                return null;
            }
            else if(c >= '0' && c <= '9') multi = multi*10 + Integer.parseInt(c+"");
            else
                ret.append(c);
        }

        return ret.toString();
    }
}

代码基本完全就是复制辅助栈法的

递归法——使用局部变量

思路基本一致,只是使用局部变量的时候,需要往回传参,但是不再需要保存递归前的全局变量了。

class Solution {/(O(n),O(n))
//当 s[i] == ']' 时,返回当前括号内记录的 res 字符串与 ] 的索引 i (更新上层递归指针位置);
//当 s[i] == '[' 时,开启新一层递归,记录此 [...] 内字符串 tmp 和递归后的最新索引 i,并执行 res + multi * tmp 拼接字符串。
//遍历完毕后返回 res。
    public String decodeString(String s) {
        return dfs(s, 0)[1];
    }
    private String[] dfs(String s, int i) {//字符串s和索引i,返回字符数组,索引i和结果string
        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]);//遇到']',i=结尾索引,即右括号位置
                while(multi>0){
                    res.append(tmp[1]);
                    multi--;
                }
            }else if(s.charAt(i)==']'){
                return new String[] {String.valueOf(i),res.toString()};
            }else{
                res.append(s.charAt(i));
            }
            i++;
        }
        return new String[] {String.valueOf(i),res.toString()};
    } 
}

总结

  • 能用迭代解决的问题,大多数时候递归都能够搞定。反之,也是一样的。
  • 使用递归的时候,应该避免使用全局变量。全局变量容易让程序变得松散。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值