代码随想录算法训练营第十一天|232.用栈实现队列、225.用队列实现栈、20.有效的括号、1047.删除字符串中的所有相邻重复项

95 阅读2分钟

232.用栈实现队列

题目连接:232.用栈实现队列

思路:利用一个栈作为辅助,在存入元素的时候调整元素的顺序,使得取出元素时符合先进先出。

class MyQueue {

    private Stack<Integer> st1;

    private Stack<Integer> st2; // 辅助栈

    public MyQueue() {
        st1 = new Stack<>();
        st2 = new Stack<>();
    }
    
    public void push(int x) {
        if (st1.empty()) {
            st1.push(x);
        } else {
            while (!st1.empty()) {
                st2.push(st1.pop());
            }
            st1.push(x);
            while (!st2.empty()) {
                st1.push(st2.pop());
            }
        }
    }
    
    public int pop() {
        return st1.pop();
    }
    
    public int peek() {
        return st1.peek();
    }
    
    public boolean empty() {
        return st1.empty();
    }
}

随想录中思路:一个栈作为输入栈,一个栈作为输出栈。在push数据的时候,直接将数据放到输入栈,在pop数据的时候,如果输出栈为空,将输入栈的数据全部导入到输出栈,如果输出栈不为空,直接pop输出栈。如果两个栈都为空,模拟队列为空。

class MyQueue {

    private Stack<Integer> stackIn;
    
    private Stack<Integer> stackOut;

    public MyQueue() {
        stackIn = new Stack<>();
        stackOut = new Stack<>();
    }
    
    public void push(int x) {
        stackIn.push(x);
    }
    
    public int pop() {
        if (stackOut.empty()) {
            while (!stackIn.empty()) {
                stackOut.push(stackIn.pop());
            }
        }
        return stackOut.pop();
    }
    
    public int peek() {
        if (stackOut.empty()) {
            while (!stackIn.empty()) {
                stackOut.push(stackIn.pop());
            }
        }
        return stackOut.peek();
    }
    
    public boolean empty() {
        return stackIn.empty() && stackOut.empty();
    }
}

225. 用队列实现栈

题目连接:225. 用队列实现栈

思路:利用一个队列作为辅助,在存入元素的时候调整元素的顺序,使得取出元素时符合先进后出。

class MyStack {

    private Queue<Integer> queue1;

    private Queue<Integer> queue2; // 辅助队列

    public MyStack() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }
    
    public void push(int x) {
        if (queue1.peek() == null) {
            queue1.offer(x);
        } else {
            while (queue1.peek() != null) {
                queue2.offer(queue1.poll());
            }
            queue1.offer(x);
            while (queue2.peek() != null) {
                queue1.offer(queue2.poll());
            }
        }
    }
    
    public int pop() {
        return queue1.poll();
    }
    
    public int top() {
        return queue1.peek();
    }
    
    public boolean empty() {
        return queue1.peek() == null;
    }
}

随想录中思路:一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时再去弹出元素就是栈的顺序了。

class MyStack {
    // Deque 接口继承了 Queue 接口
    // 所以 Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
    Deque<Integer> que1;

    public MyStack() {
        que1 = new ArrayDeque<>();
    }
    
    public void push(int x) {
        que1.addLast(x);
    }
    
    public int pop() {
        int size = que1.size() - 1;
        // 将 que1 导入 que2 ,但留下最后一个值
        while (size-- > 0) {
            que1.addLast(que1.pollFirst(););
        }
        return rque1.pollFirst();
    }
    
    public int top() {
        return que1.peekLast();
    }
    
    public boolean empty() {
        return que1.isEmpty();
    }
}

20. 有效的括号

题目连接:20. 有效的括号

思路:利用栈,当栈为空时,遍历的元素压入栈中。当遇到右括号时,如果栈中的元素和遍历的元素匹配,则弹栈,否则将元素压入栈中。最后遍历结束,如果栈为空,那么说明所有的括号匹配成功。

时间复杂度O(n)

class Solution {
    public boolean isValid(String s) {
        char[] ch = s.toCharArray();
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < ch.length; i++) {
            if (stack.empty()) {
                stack.push(ch[i]);
            } else if (ch[i] == ')' && stack.peek() == '(') {
                stack.pop();
            } else if (ch[i] == ']' && stack.peek() == '[') {
                stack.pop();
            } else if (ch[i] == '}' && stack.peek() == '{') {
                stack.pop();
            } else {
                stack.push(ch[i]);
            }
        }
        if (stack.empty()) return true;
        return false;
    }
}

随想录中的思路:一次遍历,遇到左括号,就把相应的右括号push栈中。遇到右括号,查看是否和栈中元素相同,相同弹栈,不同返回false。遍历结束后栈为空,说明匹配成功。

class Solution {
    public boolean isValid(String s) {
        Deque<Character> stack = new LinkedList<>();
        char[] ch = s.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            if (ch[i] == '(') {
                stack.push(')');
            } else if (ch[i] == '[') {
                stack.push(']');
            } else if (ch[i] == '{') {
                stack.push('}');
            } else if (stack.isEmpty() || stack.peek() != ch[i]) {
                return false;
            } else {
                stack.pop();
            }
        }
        if (stack.isEmpty()) return true;
        return false;
    }
}

1047. 删除字符串中的所有相邻重复项

题目连接:1047. 删除字符串中的所有相邻重复项

思路:为什么会想到用栈?因为和上一题有效括号一样,都是做消除操作。匹配问题时栈的强项。栈为什么适合做这种类似于爱消除的操作,因为栈帮助我们记录了遍历数组当前元素时候,前一个元素是什么。

时间复杂度O(n)

class Solution {
    public String removeDuplicates(String s) {
        // 栈为什么适合做这种类似于爱消除的操作,
        // 因为栈帮助我们记录了 遍历数组当前元素时候,前一个元素是什么。
        char[] ch = s.toCharArray();
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < ch.length; i++) {
            if (stack.empty()) {
                stack.push(ch[i]);
            } else if (ch[i] == stack.peek()) { // 如果当前元素等于栈顶元素
                stack.pop();
            } else {
                stack.push(ch[i]);
            }
        }
        StringBuilder sb = new StringBuilder();
        while (!stack.empty()) {
            sb.insert(0,stack.pop());
        }
        return sb.toString();
    }
}

与随想录中思路相同。注意事项:ArrayDeque会比LinkedList在除了删除元素这一点外会快一点。详情参考链接。