目录
🍁今日良言:须知少日拏云志,曾许人间第一流
🐎一、栈OJ题
🍂1.括号匹配
解题思路:设计一个栈,从字符串第一个字母开始遍历,遇到左括号直接入栈,遇到右括号,就开始判断栈顶数据是不是与当前右括号相匹配,如果匹配,就弹出栈顶数据,如果不匹配说明错误,当循环结束后,如果栈不为空,说明错误,为空说明正确。
图解分析:以字符串 s = "()[]{}"为例
这里需要注意一下:当i下标为右括号的话,需要先判断栈内是否有数据,如果没有的话,说明错误,有数据才进行后面栈顶与i下标括号匹配
完整代码:
class Solution {
public boolean isValid(String s) {
// 实现思路:使用栈来操作
Stack<Character> stack = new Stack<>();
// 开始遍历字符串
for (int i = 0; i < s.length();i++) {
char ch = s.charAt(i);
if (ch == '(' || ch == '{' || ch == '[') {
// 左括号入栈
stack.push(ch);
} else {
// 如果此时是右括号,但是栈为空
if (stack.empty()) {
return false;
}
// 判断栈顶是不是和当前的括号相匹配
char ret = stack.peek();
if (ch == ')' && ret == '(' ||
ch == ']' && ret == '[' || ch == '}' && ret == '{' ) {
// 此时弹出栈顶括号
stack.pop();
} else {
return false;
}
}
}
// 如果栈中还有数据说明不匹配
if (!stack.empty()) {
return false;
}
return true;
}
}
🍂2.逆波兰表达式求值
链接:150. 逆波兰表达式求值 - 力扣(LeetCode)
解题思路:设计一个栈,遍历字符串数组,遇到数字全部压入栈,遇到操作符,先弹出栈顶的两个数据(注:先弹出的是第二个操作数,后弹出的是第一个操作数),然后对操作符进行判断是何种操作,然后将两个操作数的计算结果压入栈中,for循环结束后,栈内的那个数据就是最后的计算结果。
图解分析:以 ["4","13","5","/","+"] 字符串数组为例
完整代码:
class Solution {
public int evalRPN(String[] tokens) {
// 1.遍历字符串
Stack<Integer> stack = new Stack<>();
// 2.遇到数字入栈
for (String str : tokens) {
if (!isOperation(str)) {
// 数字入栈
stack.push(Integer.parseInt(str));
} else {
// 是操作符
int num2 = stack.pop();
int num1 = stack.pop();
switch(str) {
case "+":
stack.push(num1+num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
case "/":
stack.push(num1 / num2);
break;
}
}
}
return stack.pop();
}
private boolean isOperation(String x) {
// 判断是不是字符
if (x.equals("+") || x.equals("-") || x.equals("*") || x.equals("/")) {
return true;
}
return false;
}
}
🍂3.出栈入栈次序匹配
链接:栈的压入、弹出序列_牛客题霸_牛客网 (nowcoder.com)
解题思路:设计一个栈,用一个下标j表示出栈数组的下标,然后遍历入栈数据,下标为i,先将当前i下标的数据压入栈,然后判断栈顶数据是不是与j下标的数据相同,如果相同的话就弹出栈顶数据,再让j++,再判断是否相同,显而易见,这是个while循环,注意控制循环条件,当遍历入栈数组结束后,如果栈空就正确,否则就错误。
图解分析:
以[1,2,3,4,5],[4,5,3,2,1] 数组为例
完整代码:
import java.util.*;
public class Solution {
public boolean IsPopOrder(int [] pushA, int [] popA) {
Stack<Integer> stack = new Stack<Integer>();
int j = 0;
for (int i = 0; i < pushA.length; i++) {
stack.push(pushA[i]);
while (j < popA.length && !stack.isEmpty()
&& ( stack.peek()).equals(popA[j])) {
// 弹出数据
stack.pop();
j++;
}
}
return stack.isEmpty();
}
}
🍂4.设计一个最小栈
解题思路:创建两个栈,一个stack用来存储所有数据,一个minStack用来存储最小元素。
入栈操作:stack中存放所有数据,如果minStack放入即可,如果不为空,判断当前入栈的数据与
minStack栈顶数据的大小关系,如果小于或等于可以放入,否则不能放入。
出栈操作:从stack中弹出栈顶数据,判断该数据和minStack栈顶数据是否相等,相等的话 minStack也需要进行出栈操作。
图解分析:
完整代码:
class MinStack {
private Stack<Integer> stack;
private Stack<Integer> minStack;// 每次存放最小的元素
public MinStack() {
stack = new Stack<>();
minStack = new Stack<>();
}
public void push(int val) {
// stack 都要放入数据
stack.push(val);
// 如果最小元素栈为空直接放入
if (minStack.empty()) {
minStack.push(val);
} else {
// 不为空的话 判断minStack栈顶的数据与当前val值的大小
// 小于等于就放 大于不放
int x = minStack.peek();
if (val <= x) {
minStack.push(val);
}
}
}
public void pop() {
if (!stack.empty()) {
// 先将stack栈顶元素出栈 然后比较与minStack栈顶数据的大小
int x = stack.pop();
if (x == minStack.peek()) {
// 相等则出栈
minStack.pop();
}
}
}
public int top() {
if (!stack.empty()) {
return stack.peek();
}
return -1;
}
public int getMin() {
if (minStack.empty()) {
return -1;
}
return minStack.peek();
}
}
🐎二、队列OJ题
☘️1.设计循环队列
之前写过一篇文章,对于循环队列(取模队列)详细的实现,这里就不再赘述:
(1条消息) 如何用数组实现固定大小的队列重复利用?_qq_54469537的博客-CSDN博客
力扣完整代码:
class MyCircularQueue {
private int[] elem;
private int front;// 队头
private int rear;// 队尾
public MyCircularQueue(int k) {
elem = new int[k+1];
}
// 插入数据
public boolean enQueue(int value) {
// 先判满
if (isFull()) {
return false;
}
// 没满就放数据
elem[rear] = value;
rear = (rear+1)%elem.length;
return true;
}
// 删除队头元素
public boolean deQueue() {
if (isEmpty()) {
return false;
}
front = (front+1)%elem.length;
return true;
}
// 队头数据
public int Front() {
if (isEmpty()) {
return -1;
}
return elem[front];
}
// 队尾数据
public int Rear() {
if (isEmpty()) {
return -1;
}
// 要注意rear的位置
int index = rear == 0? elem.length-1:rear-1;
return elem[index];
}
public boolean isEmpty() {
return rear == front;
}
// 判满
public boolean isFull() {
if ((rear + 1) % elem.length == front) {
return true;
}
return false;
}
}
☘️2.用队列实现栈
解题思路:创建两个队列qu1 和 qu2
入栈操作: 判断哪个队列不为空就放入哪个队列,如果都为空,就放入qu1中
出栈操作:判断哪个队列不为空,假设qu1不为空,存放的数据个数为size,for循环,将size-1个数据放入到qu2中,则qu1中存放的最后那个数据就是栈顶数据,然后弹出即可。qu2不为空则同理。
查看栈顶数据: 与出栈操作类似,设置一个辅助变量ret,判断哪个队列不为空,则将该队列的所有数据取出放入到另一个队列中,用ret每次记录取出的数据,最后返回的ret就是栈顶数据。
图解分析:
完整代码:
class MyStack {
Queue<Integer> que1;
Queue<Integer> que2;
public MyStack() {
que1 = new LinkedList<>();
que2 = new LinkedList<>();
}
public void push(int x) {
if (!que1.isEmpty()) {
que1.offer(x);
} else if (!que2.isEmpty()){
que2.offer(x);
} else {
que1.offer(x);
}
}
// 首先将不为空的队列中的数据的前size-1个数据全部放入为空的队列
public int pop() {
if (empty()) {
return -1;
}
if (!que1.isEmpty()) {
int size = que1.size();
for (int i = 0; i < size - 1;i++) {
que2.offer(que1.poll());
}
return que1.poll();
} else {
int size = que2.size();
for (int i = 0; i < size - 1;i++) {
que1.offer(que2.poll());
}
return que2.poll();
}
}
// 读取栈顶数据
public int top() {
if (empty()) {
return -1;
}
if (!que1.isEmpty()) {
int size = que1.size();
int ret = -1;// 保留每次弹出的数据
for (int i = 0; i < size;i++) {
ret = que1.poll();
que2.offer(ret);
}
return ret;
} else {
int size = que2.size();
int ret = -1;// 保留每次弹出的数据
for (int i = 0; i < size;i++) {
ret = que2.poll();
que1.offer(ret);
}
return ret;
}
}
public boolean empty() {
return que1.isEmpty() && que2.isEmpty();
}
}
☘️3.用栈实现队列
解题思路:设计两个栈s1和s2 ,s1用来入队列操作 s2用来出队列和查看队头数据
入队列操作:将所有数据都放入s1中
出队列操作: 先判断s2中是否有数据,没有的话,循环将s1中的数据全部放入s2中,则此时s2栈顶的数据就是要出的队头数据,弹出即可。
查看队头数据:与出队列操作相同,最后查看s2栈顶数据即可。
图解分析:
完整代码:
class MyQueue {
Stack<Integer> s1 ;
Stack<Integer> s2;
public MyQueue() {
s1 = new Stack<>();
s2 = new Stack<>();
}
public void push(int x) {
s1.push(x);
}
public int pop() {
if (empty()) {
return -1;
}
if (s2.empty()) {
// 将s1中的数据放入s2中再弹出
while (!s1.empty()) {
s2.push(s1.pop());
}
}
return s2.pop();
}
public int peek() {
if (empty()) {
return -1;
}
if (s2.empty()) {
// 将s1中的数据放入s2中再弹出
while (!s1.empty()) {
s2.push(s1.pop());
}
}
return s2.peek();
}
public boolean empty() {
return s1.empty() && s2.empty();
}
}