leetcode-394-字符串解码-java

题目及测试

package pid394;
/*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"


*/


public class main {
	
	public static void main(String[] args) {
		String [] testTable = {"3[a]2[bc]","3[a2[c]]","2[abc]3[cd]ef"};
		for (String ito : testTable) {
			test(ito);
		}
	}
		 
	private static void test(String ito) {
		Solution solution = new Solution();
		String rtn;
		long begin = System.currentTimeMillis();
		System.out.print(ito);		    
		System.out.println();
		//开始时打印数组
		
		rtn= solution.decodeString(ito);//执行程序
		long end = System.currentTimeMillis();	
		
		System.out.println("rtn=" );
		System.out.print(rtn);
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,3ms,较慢)

建立一个装char元素的stack,对字符串s进行遍历,遇到除了 ] 之外的元素,就加入stack,遇到],开始逻辑。

首先找到[ ]之间的字符串base,然后找到[]前面的数字realNum,然后生成一个字符串base的realNum次=result,最后把result再逐个加入stack。

遍历完后,stack里都是字符,依次加入result后,反转即可。

package pid394;

import java.util.Stack;

class Solution {
    public String decodeString(String s) {
    	int length = s.length();
    	if(length == 0){
    		return "";
    	}
    	Stack stack = new Stack<>();
    	for(int i = 0;i < length;i++){
    		char now = s.charAt(i);
    		if(now != ']'){
    			stack.push(now);
    		}else{
    			// 先不断pop找到[,得到[]之中的字符串
    			StringBuilder base = new StringBuilder();
    			while(true){
    				char c = stack.pop();
    				if(c == '['){
    					break;
    				}else{
    					base.append(c);
    				}
    			}
    			// 由于之前的是后面的在前,所以颠倒
    			base = base.reverse();
    			// 找到[]前对应的数字
    			StringBuilder num = new StringBuilder();
    			while(!stack.isEmpty()){
    				char c = stack.pop();
    				if(c < '0' || c > '9'){
    					stack.push(c);
    					break;
    				}else{
    					num.append(c);
    				}
    			}
    			num = num.reverse();
    			int realNum = Integer.valueOf(num.toString());
    			// 得到base*realNum次
    			StringBuilder result = new StringBuilder();
    			for(int j=0;j

解法2(别人的)

本题中可能出现括号嵌套的情况,比如 2[a2[bc]],这种情况下我们可以先转化成 2[abcbc],在转化成 abcbcabcbc。我们可以把字母、数字和括号看成是独立的 TOKEN,并用栈来维护这些 TOKEN。具体的做法是,遍历这个栈:

如果当前的字符为数位,解析出一个数字(连续的多个数位)并进栈

如果当前的字符为字母或者左括号,直接进栈

如果当前的字符为右括号,开始出栈,一直到左括号出栈,出栈序列反转后拼接成一个字符串,此时取出栈顶的数字(此时栈顶一定是数字,想想为什么?),就是这个字符串应该出现的次数,我们根据这个次数和字符串构造出新的字符串并进栈

重复如上操作,最终将栈中的元素按照从栈底到栈顶的顺序拼接起来,就得到了答案。注意:这里可以用不定长数组来模拟栈操作,方便从栈底向栈顶遍历。

class Solution {
    int ptr;

    public String decodeString(String s) {
        LinkedList stk = new LinkedList();
        ptr = 0;

        while (ptr < s.length()) {
            char cur = s.charAt(ptr);
            if (Character.isDigit(cur)) {
                // 获取一个数字并进栈
                String digits = getDigits(s);
                stk.addLast(digits);
            } else if (Character.isLetter(cur) || cur == '[') {
                // 获取一个字母并进栈
                stk.addLast(String.valueOf(s.charAt(ptr++))); 
            } else {
                ++ptr;
                LinkedList sub = new LinkedList();
                while (!"[".equals(stk.peekLast())) {
                    sub.addLast(stk.removeLast());
                }
                Collections.reverse(sub);
                // 左括号出栈
                stk.removeLast();
                // 此时栈顶为当前 sub 对应的字符串应该出现的次数
                int repTime = Integer.parseInt(stk.removeLast());
                StringBuffer t = new StringBuffer();
                String o = getString(sub);
                // 构造字符串
                while (repTime-- > 0) {
                    t.append(o);
                }
                // 将构造好的字符串入栈
                stk.addLast(t.toString());
            }
        }

        return getString(stk);
    }

    public String getDigits(String s) {
        StringBuffer ret = new StringBuffer();
        while (Character.isDigit(s.charAt(ptr))) {
            ret.append(s.charAt(ptr++));
        }
        return ret.toString();
    }

    public String getString(LinkedList v) {
        StringBuffer ret = new StringBuffer();
        for (String s : v) {
            ret.append(s);
        }
        return ret.toString();
    }
}

解法3(别人的)

我们也可以用递归来解决这个问题,从左向右解析字符串:

如果当前位置为数字位,那么后面一定包含一个用方括号表示的字符串,即属于这种情况:k[...]:

我们可以先解析出一个数字,然后解析到了左括号,递归向下解析后面的内容,遇到对应的右括号就返回,此时我们可以根据解析出的数字 x 解析出的括号里的字符串 s′ 构造出一个新的字符串 x × s′;

我们把 k[...] 解析结束后,再次调用递归函数,解析右括号右边的内容。

如果当前位置是字母位,那么我们直接解析当前这个字母,然后递归向下解析这个字母后面的内容。

如果觉得这里讲的比较抽象,可以结合代码理解一下这个过程。

class Solution {
    String src;
    int ptr;

    public String decodeString(String s) {
        src = s;
        ptr = 0;
        return getString();
    }

    public String getString() {
        if (ptr == src.length() || src.charAt(ptr) == ']') {
            // String -> EPS
            return "";
        }

        char cur = src.charAt(ptr);
        int repTime = 1;
        String ret = "";

        if (Character.isDigit(cur)) {
            // String -> Digits [ String ] String
            // 解析 Digits
            repTime = getDigits(); 
            // 过滤左括号
            ++ptr;
            // 解析 String
            String str = getString(); 
            // 过滤右括号
            ++ptr;
            // 构造字符串
            while (repTime-- > 0) {
                ret += str;
            }
        } else if (Character.isLetter(cur)) {
            // String -> Char String
            // 解析 Char
            ret = String.valueOf(src.charAt(ptr++));
        }
        
        return ret + getString();
    }

    public int getDigits() {
        int ret = 0;
        while (ptr < src.length() && Character.isDigit(src.charAt(ptr))) {
            ret = ret * 10 + src.charAt(ptr++) - '0';
        }
        return ret;
    }
}

 

 

你可能感兴趣的:(leetcode,leetcode-中等,数据结构-栈)