栈与队列–有关题型
第一题:括号匹配问题
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
1.左括号必须用相同类型的右括号闭合。
2.左括号必须以正确的顺序闭合。
解题思路:需要使用栈来完成
1.遍历字符串,如果当前是左括号,就入栈.
2.如果当前是右括号,就拿这个右括号和当前的栈顶元素进行比较,看看是不是匹配的括号.
如果匹配,就把栈顶元素出栈,继续遍历下一个字符.
如果不匹配,就说明当前的字符是非法的.
3.当字符串遍历结束之后,并且栈也同时为空,此时说明整个字符串是一个合法情况.
代码如下:
class Solution {
public boolean isValid(String s) {
//首先需要创建一个栈.
Stack<Character> stack = new Stack<>();
//遍历字符串.
for(int i = 0;i < s.length();i++) {
char c = s.charAt(i);
//如果遇到左括号,就入栈.
if (c == '(' || c == '[' || c == '{') {
stack.push(c);
continue;
}
//右括号(题目中要求只包含括号,没有其他字符)
//取栈顶元素和当前的括号匹配.
//注意,标准库中的Stcak,在针对空栈进行peek时会直接抛异常.
if (stack.isEmpty()) {
return false;
}
Character top = stack.pop();
if (top == '(' && c == ')') {
continue;
}
if (top == '[' && c == ']') {
continue;
}
if (top == '{' && c == '}') {
continue;
}
//如果没有触发到上面合法的三种情况,则此时就是非法情况,直接返回false
return false;
}
//循环结束,说明字符串已经遍历完.
//此时还需要判定一下,栈是否为空.
if(stack.isEmpty()){
return true;
}
return false;
}
}
第二题:用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通队列的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
解题思路:重点在于倒腾.
两个队列A和B
1.使用队列A用来进行入栈操作,使用队列B用来辅助进行倒腾.
2.针对MyStack 进行入栈,就把新元素插入到队列A中,继续再进行入栈,仍然往A中插入.
3.针对MyStack 进行出栈(注意,此时先进先出),对A中的元素进行出队列操作,将最后一个出队列的元素删掉(即不再进入队列B),就完成出栈操作.
4.为了方便下次插入,将A和B调换位置,以保证B始终是辅助进行出栈的队列,A始终是辅助进行入栈的队列.
5.取栈顶元素操作和出栈操作大同小异,即取栈顶元素和出栈的唯一区别就是把A中的最后一个还要再塞回B中.
代码如下
class MyStack {
private Queue<Integer> A = new LinkedList<>();
private Queue<Integer> B = new LinkedList<>();
public MyStack() {
}
public void push(int x) {
//入栈时,直接往A中插入.
A.offer(x);
}
public int pop() {
//出栈时,把A中的元素往B中倒腾,当A中只剩一个元素的时候
//最后这个元素就是被删除的元素.
if(A.isEmpty() && B.isEmpty()){
//针对空栈的判定.
//注意,题目要求的方法不是Integer,就无法返回null,只能随便返回一个值.
return 0;
}
while(A.size() > 1){
int tmp = A.poll();
B.offer(tmp);
}
//当上面的循环结束,此时A中就只剩下一个元素
//把这个最后的元素作为出栈的结果即可.
int ret = A.poll();
//最终完成操作之后,交换A和B,保证下次入栈还是往A中插入.
swapAB();
return ret;
}
private void swapAB(){
Queue<Integer> tmp = A;
A = B;
B = tmp;
}
public int top() {
//取栈顶元素和出栈的唯一区别
//在于取栈顶元素时把A中的最后一个还要再塞回B中
if(A.isEmpty() && B.isEmpty()){
return 0;
}
while(A.size() > 1){
int tmp = A.poll();
B.offer(tmp);
}
int ret = A.poll();
B.offer(ret);
swapAB();
return ret;
}
public boolean empty() {
return A.isEmpty() && B.isEmpty();
}
}
第三题:用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾。
int pop() 从队列的开头移除并返回元素。
int peek() 返回队列开头的元素。
boolean empty() 如果队列为空,返回 true ;否则,返回 false。
解题思路:重点在于倒腾.
两个栈A和B
A专门辅助进行入队列
B专门辅助进行出队列
1.A专门辅助进行入队列, B专门辅助进行出队列.
2.针对MyStack 进行入队列,就把新元素插入到A中.
3.针对MyStack 进行出队列,把A中的元素往B中倒腾,当A中只剩一个元素的时候,这个元素就是要被出队列的元素.
注意:此处不用交换A和B
如果继续入队列,仍然是往A中插入,但是往A中插入之前,需要先把B中的元素给倒腾回来.
4.取队首元素操作和出队列操作相同,也是先倒腾到B中,然后取B的栈顶元素即可.
代码如下
class MyQueue {
Stack<Integer> A =new Stack<>();
Stack<Integer> B =new Stack<>();
/** Initialize your data structure here. */
public MyQueue() {
}
public void push(int x) {
//入队列时,需要先把B中的元素倒腾到A中,再往A中插入新元素.
while(!B.isEmpty()){
int tmp = B.pop();
A.push(tmp);
}
A.push(x);
}
public int pop() {
if(A.isEmpty() && B.isEmpty()) {
return 0;
}
//把A中的元素往B中倒腾,剩下的最后一个元素就是要被出队列的元素.
// while(A.size() > 1) {
// int tmp = A.pop();
// B.push(tmp);
// }
//此时取到的就是最后一个元素,也就是队首元素.
// int ret = A.pop();
// return ret;
//使用上面的代码,在进行连续多次pop/peek时会存在问题.
//更优解,先把A的所有元素都倒腾到B中,然后再通过B进行pop.
while(!A.isEmpty()){
int tmp = A.pop();
B.push(tmp);
}
//删除B中的元素.
return B.pop();
}
public int peek() {
if(A.isEmpty() && B.isEmpty()) {
return 0;
}
// while(A.size() > 1) {
// int tmp = A.pop();
// B.push(tmp);
// }
// int ret = A.pop();
//取队首元素和出队列的唯一区别
//在于取队首元素时把A中的最后一个还要再倒腾到B中.
// B.push(ret);
// return ret;
while(!A.isEmpty()){
int tmp = A.pop();
B.push(tmp);
}
return B.peek();
}
第四题
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
解题思路:题目要求以O(1)来得到最小值.
两个栈A和B
B中的内容就是由一系列"当前"的最小值构成.
每次给A中插入元素,都需要拿A的这个元素和B的栈顶进行对比,把最小值入到B中.
后续需要获取最小值,直接从B的栈顶来取.
如果对A出栈,也同步对B出栈,出栈元素后,B的栈顶仍然是A的最小值.
代码如下
class MinStack {
//创建两个栈.
Stack<Integer> A = new Stack<>();
//B里存的就是当前A的最小值.
Stack<Integer> B = new Stack<>();
public MinStack() {
}
public void push(int x) {
//先把x插入A中.
A.push(x);
//比较x和B的栈顶,看谁小,谁小就插入谁.
if(B.isEmpty()){
B.push(x);
return;
}
int min = B.peek();
if(x < min){
min = x;
}
B.push(min);
}
public void pop() {
if(A.isEmpty()){
return;
}
A.pop();
B.pop();
}
public int top() {
if(A.isEmpty()){
return 0;
}
return A.peek();
}
public int getMin() {
if(B.isEmpty()){
return 0;
}
return B.peek();
}
}