leetcode刷题记录day030:225和394

225、难度简单:

方法一:两个队列:时空复杂度:O(n)

要求:实现每种操作的均摊时间复杂度为 O(1) 的栈(换句话说,执行 n 个操作的总时间复杂度 O(n) ,尽管其中某个操作可能需要比其他操作更长的时间。可以使用两个以上的队列)

class MyStack {
    Queue<Integer> queue1; // 用于存储栈内的元素
    Queue<Integer> queue2; // 作为入栈操作的辅助队列

    /** Initialize your data structure here. */
    public MyStack() {
        queue1 = new LinkedList<Integer>();
        queue2 = new LinkedList<Integer>();
    }
    
    // 要解决的点是栈从最顶部取元素,而队列从最底部开始取。所以需要让队列逆序数据
    // 首先将元素入队到queue2,然后将queue1的全部元素(原先排好栈顺序的)依次出队并入队到queue2
    // (由于队列的特点,一队列把自己的全值给另一队列,二者数据顺序相同)
    // 此时queue2的前端的元素即为新入栈的元素,再将queue1和queue2互换,
    // 则queue1的元素即为栈内的元素,queue1的前端和后端分别对应栈顶和栈底
    public void push(int x) {
        queue2.offer(x);
        while (!queue1.isEmpty()) {
            queue2.offer(queue1.poll());
        }
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }
    
    // 队列queue1对元素的入出队列顺序已经和栈的方式相同了,直接弹出来就行
    public int pop() {
        return queue1.poll();
    }
    
    /** Get the top element. */
    public int top() {
        return queue1.peek();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue1.isEmpty();
    }
}
方法二:一个队列:时空复杂度:O(n)
class MyStack {
    Queue<Integer> queue;

    /** Initialize your data structure here. */
    public MyStack() {
        queue = new LinkedList<Integer>();
    }
    
    // 首先获得入栈前的元素个数 n,然后将元素入队到队列,
    // 再将队列中的前 n 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,
    // 此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底
    public void push(int x) {
        int n = queue.size();
        queue.offer(x);
        for (int i = 0; i < n; i++) {
            queue.offer(queue.poll());
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return queue.poll();
    }
    
    /** Get the top element. */
    public int top() {
        return queue.peek();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue.isEmpty();
    }
}

394、难度中等:

本题和"20、有效的括号"类似,都需要用栈来解决形如"3[ a 2[ c ] ]、{ [ ] }"的嵌套问题

方法一:栈操作:

原理:本题中可能出现括号嵌套的情况,比如 2[a2[bc]],这种情况下我们可以先转化成 2[abcbc],在转化成 abcbcabcbc
遍历题传字符串:
1、如果当前的字符为数位,解析出一个数字(可能是连续的多个数位,比如36、100)并进栈
2、如果当前的字符为字母或者左括号,直接进栈
3、如果当前的字符为右括号,开始出栈,一直到左括号出栈,出栈序列反转后拼接成一个字符串,此时取出栈顶的数字(此时栈顶一定是数字,想想为什么?),就是这个字符串应该出现的次数,我们根据这个次数和字符串构造出新的字符串并进栈

class Solution {
    int ptr;

    public String decodeString(String s) {
        LinkedList<String> stk = new LinkedList<String>(); // 作为返回的结果
        ptr = 0; // 作为题给字符串的下标

        while (ptr < s.length()) {
            char cur = s.charAt(ptr);
            // 入结果栈数字
            if (Character.isDigit(cur)) {
                // 获取一个数字并进栈,由于其后可能还存在数字凑成两位、三位数等,所以调用方法getDigits
                String digits = getDigits(s);
                stk.addLast(digits);
            // 入结果栈字母
            } else if (Character.isLetter(cur) || cur == '[') {
                // 获取一个字母并进栈
                stk.addLast(String.valueOf(s.charAt(ptr++))); 
            // 数字*字符串:既不是数字也不是英文字母那就是"["或"]"
            } else {
                ++ptr;
                // 创建新栈(每次被执行到都创建一个新的),用来保存一个[纯英文字母]里的纯英文字母集合
                LinkedList<String> sub = new LinkedList<String>();
                // 持续弹出栈stk里的元素,一直到遇见"["为止,此时sub栈里有一个完整的[...]里的...
                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());
            }
        }
	    // 调用我们自己写的getString方法,将栈里的所有元素字符串化
        return getString(stk);
    }
	
    // 返回数字用:
    // 遍历题给字符串 s 得到一个字符数字,但该数字是一位的,有可能后面还存在一位(比如"36"、"100")
    // 所以需要获取完整的整数
    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<String> v) {
        StringBuffer ret = new StringBuffer();
        for (String s : v) {
            ret.append(s);
        }
        return ret.toString();
    }
}

在看完以上代码后可能会异或代码是如何解决 2[a2[bc]]格式的:
首先第一轮入栈 stk 循环会一直持续到元素 c 后的 ] 为止,然后我们开始将字符 c、b依次存入另一个栈 sub 中,再逆序为 b、c,乘2后存入到 stk,此时 stk 里的内容为 “2”、"["、“a”、“bcbc”。
进入下一轮循环,遇到 ] 所以执行while (!"[".equals(stk.peekLast())) {,得到的是 bcbc、a 再逆序为 a、bcbc,乘2存入stk中。代码结束返回abcbcabcbc

方法二:递归:涉及到《编译原理》相关内容,详细看下方链接

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/decode-string/solution/zi-fu-chuan-jie-ma-by-leetcode-solution/

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;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeYello

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值