栈和队列

栈:FILO先入后出。

队列:  FIFO先入先出。

 

1. 设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。
 

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/queue-stack/kzlb5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

class MyCircularQueue {
    int head;
    int tail;
    int size;
    int[] tab;

    public MyCircularQueue(int k) {
        tab = new int[k];
        head = 0;
        tail = -1;
    }
    
    public boolean enQueue(int value) {
        if(isFull()) {
            return false;
        }
        tail++;
        tail = tail % tab.length;
        tab[tail] = value;
        
        size++;
        return true;
    }
    
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        tab[head++] = -1;
        head = head % tab.length;
        size--;
        return true;
    }
    
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        
        return tab[head];
    }
    
    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        return tab[tail];
    }
    
    public boolean isEmpty() {
        return size == 0;
    }
    
    public boolean isFull() {
        return size >= tab.length;
    }
}

2. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true
示例 2:

输入: "()[]{}"
输出: true
示例 3:

输入: "(]"
输出: false
示例 4:

输入: "([)]"
输出: false
示例 5:

输入: "{[]}"
输出: true

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/queue-stack/g9d0h/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解题思路:此题可以用栈来解,把左括号压入栈中,碰到右括号就从栈中弹出进行匹配,如果不匹配就返回false.

class Solution {
    public boolean isValid(String s) {
        ArrayDeque<Character> stack = new ArrayDeque<>();
        for(int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if(stack.isEmpty()) {
                stack.push(ch);
                continue;
            }
            switch(ch){
                case '}' :
                    if(stack.poll() != '{') return false;
                    break;
                case ']' :
                    if(stack.poll() != '[') return false;
                    break;
                case ')' :
                    if(stack.poll() != '(') return false;
                    break;
                default : stack.push(ch);
            }
            ;
        }
        if(stack.isEmpty()) {
            return true;
        }
        return false;
    }
}
 
3. 每日温度

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/queue-stack/genw3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

class Solution {
    public int[] dailyTemperatures(int[] T) {
        ArrayDeque<Integer> arrayDeque = new ArrayDeque();
        int[] result = new int[T.length];

        for(int i = 0; i < T.length; i++) {
            if(arrayDeque.isEmpty() || T[arrayDeque.peek()] >= T[i]) {
                arrayDeque.push(i);
            } else{
                while(!arrayDeque.isEmpty() && T[arrayDeque.peek()] < T[i] ){
                    int index = arrayDeque.pop();
                    result[index] = i - index;
                }
                arrayDeque.push(i);
            }
        }

        return result;
    }
}
 
4. 逆波兰表达式求值

根据 逆波兰表示法,求表达式的值。

有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

 

说明:

整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
 

示例 1:

输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:

输入: ["4", "13", "5", "/", "+"]
输出: 6
解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/queue-stack/gomvm/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解题思路: 碰到算术题,使用栈解决。碰到数字就压栈,碰到运算符,就弹出栈中的两个数字进行运算,把运算结果压入栈。

class Solution {
    public int evalRPN(String[] tokens) {
        ArrayDeque<Integer> arrayDeque = new ArrayDeque<>();
        int num2;
        int num1;
        for(String s : tokens) {
            switch(s) {
                case "+" : 
                    num2 = arrayDeque.pop();
                    num1 = arrayDeque.pop();
                    arrayDeque.push(num1 + num2);
                    break;
                case "-":
                    num2 = arrayDeque.pop();
                    num1 = arrayDeque.pop();
                    arrayDeque.push(num1 - num2);
                    break;
                case "*":
                    num2 = arrayDeque.pop();
                    num1 = arrayDeque.pop();
                    arrayDeque.push(num1 * num2);
                    break;
                case "/":
                    num2 = arrayDeque.pop();
                    num1 = arrayDeque.pop();
                    arrayDeque.push(num1 / num2);
                    break; 
                default: arrayDeque.push(Integer.valueOf(s));
            }
        }
        return arrayDeque.pop();
    }
}
 
 5.用栈实现队列
 

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列的支持的所有操作(push、pop、peek、empty):

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
 

说明:

你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

示例:

输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]

解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/queue-stack/gvtxe/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class MyQueue {
    ArrayDeque<Integer> stack1;
    ArrayDeque<Integer> stack2;

    /** Initialize your data structure here. */
    public MyQueue() {
        stack1 = new ArrayDeque<>();
        stack2 = new ArrayDeque<>();
    }
    
    /** Push element x to the back of queue. */
    public void push(int x) {
        if(empty()) {
            stack1.push(x);
        } else{
            while(!stack1.isEmpty()) {
                stack2.push(stack1.pop());
            }
            stack2.push(x);

            while(!stack2.isEmpty()) {
                stack1.push(stack2.pop());
            }
        }

    }
    
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        return stack1.pop();
    }
    
    /** Get the front element. */
    public int peek() {
        return stack1.peek();
    }
    
    /** Returns whether the queue is empty. */
    public boolean empty() {
        return stack1.isEmpty();
    }
}

 

6. 用队列实现栈

使用队列实现栈的下列操作:

push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空
注意:

你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/queue-stack/gw7fg/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class MyStack {
    LinkedList<Integer> queue1;
    LinkedList<Integer> queue2;

    /** Initialize your data structure here. */
    public MyStack() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        if(empty()) {
            queue1.add(x);
        } else {
            while(!queue1.isEmpty()) {
                queue2.add(queue1.poll());
            }
            queue1.add(x);
            while(!queue2.isEmpty()) {
                queue1.add(queue2.poll());
            }
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    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();
    }
}
 

7.字符串解码

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

编码规则为: 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"

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/queue-stack/gdwjv/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

解题思路:通过压栈把字符,数字和[压入。当碰到 ] 时。弹出栈知道出现 [ 结束、

class Solution {
    private int ptr = 0;
    public String decodeString(String s) {
        if(s == null || s.length() <= 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        ArrayDeque<String> stack = new ArrayDeque<>();

        while(ptr < s.length()) {
            char ch = s.charAt(ptr);
            if (Character.isDigit(ch)) {
                stack.push(getDigits(s));
            } else if(Character.isLetter(ch) || ch == '[') {
                stack.push(String.valueOf(ch));
                ptr++;
            } else {
                ptr++;
                LinkedList<String> subList = new LinkedList<>();
                int repeat = 0;
                while(!"[".equals(stack.peek())) {
                    subList.addFirst(stack.pop());
                }
                String subStr = getString(subList);
                stack.pop();
                repeat = Integer.valueOf(stack.pop());
                StringBuilder subSb = new StringBuilder();
                while(repeat-- > 0) {
                    subSb.append(subStr);
                }
                stack.push(subSb.toString());
            }

        }
        while(!stack.isEmpty()) {
            sb.append(stack.pollLast());
        }

        return sb.toString();
    }

    private String getString(LinkedList<String> subList) {
        StringBuilder sb = new StringBuilder();
        for(String str : subList) {
            sb.append(str);
        }

        return sb.toString();
    }

    private String getDigits(String s) {
        StringBuilder sb = new StringBuilder();
        while(Character.isDigit(s.charAt(ptr))){
            sb.append(s.charAt(ptr++));
        }
        return sb.toString();
    }
}
posted @ 2020-12-25 17:37  闪闪的星光  阅读(127)  评论(0)    收藏  举报