队列和栈
队列是一种线性结构,但是它只能从头尾插入和删除,并且遵守先进先出(FIFO)的规则。在java中有两个接口Queue(单向队列)和Deque(双向队列)。紧接着我们来捋一下继承关系。
Queue与Deque方法:
Queue方法:
作用 | 第一组 | 第二组 |
---|---|---|
插入 | boolean add(E e) | boolean Offer(E e) |
删除队首元素 | E remove() | E poll() |
查看队首元素 | E element() | E peek() |
区别 | 通过异常通知调用者发生错误 | 通过特殊返回值通知调用者发生错误 |
趁热打铁,那么对应的双向队列也是这样区分的,不同的是双向队列既然是双向的那么就有了头和尾的对应操作。
Deque方法:
Deque继承自Queue,所以Queue中的方法,在Deque中也是对应的。
这张图我们用的是addLast、getFirst和removeFirst,那么如果把这张图旋转90°会发生什么事呢?
所以Deque既可以当做一个队列,也可以当做一个栈,重点记忆以下方法:
队列 | 栈 | |
---|---|---|
构造 | Queue<泛型> queue = new LinkedList<>() | Deque<泛型> stack = new LinkedList<>() |
插入 | queue.add() | stack.push() |
删除 | queue.remove() | stack.pop() |
查看 | queue.element() | stack.peek() |
题目一:有效的括号
每道题都有链接,点击跳转。
LeetCode题目链接
伪代码:
准备好一个存放字符的栈
遍历String字符串的每一个字符
根据字符不同,进行不同的处理:
- 如果是左括号:{([,统一压入栈中
- 如果是右括号:则需要从栈顶带走一个元素
- 栈为空->说明右括号多了,返回false
- 栈不为空,但栈顶的左括号和现在的又括号不匹配->错误
- 成功匹配,并将栈顶元素弹出
再进行检查栈是否为空
- 如果栈为空->左括号多了,错误
- 如果栈为空->正确
import java.util.Deque;
import java.util.LinkedList;
public class Solution20 {
public boolean isValid(String s){
Deque<Character> stack = new LinkedList<>();
char[] charArray = s.toCharArray();
for(char c : charArray){
switch (c){
case '{':
case '[':
case '(':
//因为没有break,所以,无论是哪个都会之下到下一行
stack.push(c);
break;
default:{
//一定是右括号
if(stack.isEmpty()){
//右括号多了
return false;
}
//否则取出栈顶元素
char left = stack.pop();
//进行左右括号的比较
if(!compareBracket(left,c)){
//左括号和又括号不匹配
return false;
}
}
}
}
if(stack.isEmpty()){
return true;
}else{
//左括号多了
return false;
}
}
private boolean compareBracket(char left,char right){
if(left == '(' && right == ')'){
return true;
}
if(left == '[' && right == ']'){
return true;
}
if(left == '{' && right == '}'){
return true;
}
//除了上面这三种情况以外的所有情况都是不匹配
return false;
}
}
题目二:用队列实现栈
class MyStack {
public Queue<Integer> queue;
/** Initialize your data structure here. */
public MyStack() {
queue = new LinkedList<>();
}
/** Push element x onto stack. */
public void push(int x) {
queue.add(x);
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
int size = queue.size();
for(int i = 0;i < size - 1;i++){
Integer e = queue.remove();
queue.add(e);
}
return queue.remove();
}
/** Get the top element. */
public int top() {
Integer e = pop();
queue.add(e);
return e;
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue.isEmpty();
}
}
题目三:用栈实现队列
如果理解了题目二,那么对于这道题的理解也就容易多了
分析:左栈s1,右栈s2
push():只管压入s2栈中
pop():
判断s1栈是否为空
空:把s2栈中的所有元素,先取出,再压入s1栈中,直到s2为空,弹出s1栈顶元素。
非空:直接从s1栈中,弹出一个元素。
peek():
与pop基本相同,不过pop最后是弹出s1栈顶元素,而peek是查看s1栈顶元素。
empty():
判断s1和s2是否为空即可
class MyQueue {
public Deque<Integer> s1;
public Deque<Integer> s2;
/** Initialize your data structure here. */
public MyQueue() {
s1 = new LinkedList<>();
s2 = new LinkedList<>();
}
/** Push element x to the back of queue. */
public void push(int x) {
s2.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
if(s1.isEmpty()){
while(!s2.isEmpty()){
Integer e = s2.pop();
s1.push(e);
}
}
return s1.pop();
}
/** Get the front element. */
public int peek() {
if(s1.isEmpty()){
while(!s2.isEmpty()){
Integer e = s2.pop();
s1.push(e);
}
}
return s1.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
return s1.isEmpty() && s2.isEmpty();
}
}
题目四:最小栈
class MinStack {
public Deque<Integer> s1;
public Deque<Integer> s2;
/** initialize your data structure here. */
public MinStack() {
s1 = new LinkedList<>();
s2 = new LinkedList<>();
}
public void push(int x) {
s1.push(x);
if(s2.isEmpty() || s2.peek() >= x){
s2.push(x);
}
}
public void pop() {
int e = s1.pop();
if(s2.peek() == e){
s2.pop();
}
}
public int top() {
return s1.peek();
}
public int getMin() {
return s2.peek();
}
}
题目五:栈的压入、弹出序列
解析:
判断栈的弹出顺序,整体思路就是通过压栈元素与弹栈元素进行匹配,合理则为true,不合理则为false。
- 很明显需要一个栈来辅助操作。
- 如果栈为空或者弹出序列首元素与栈顶元素不相等:
- 如果入栈序列为空,则说明错误,因为没有可以进行匹配的元素了。
- 否则就让入栈序列首元素入栈
- 循环操作
- 当循环退出,说明已经匹配到了,那就直接让栈顶元素弹出去(入栈元素与出栈元素同时丢掉)
- 如果最后都匹配到了,则栈为空,true。
public class Solution {
//数组不能通过length判断是否为空,通过几个下标判断会比较麻烦
//所以这里使用队列来转换了一下
private Queue<Integer> intArrayToQueue(int[] array){
Queue<Integer> queue = new LinkedList<>();
for(int n : array){
queue.add(n);
}
return queue;
}
public boolean IsPopOrder(int[] pushA,int[] popA){
Queue<Integer> pushQueue = intArrayToQueue(pushA);
Queue<Integer> popQueue = intArrayToQueue(popA);
//实现准备的栈
Deque<Integer> stack = new LinkedList<>();
while(!popQueue.isEmpty()){
int p = popQueue.remove();
while(stack.isEmpty() || stack.peek() != p){
if(pushQueue.isEmpty()){
return false;
}
int q = pushQueue.remove();
stack.push(q);
}
stack.pop();
}
return stack.isEmpty();
}
}