1. <tag-队列和栈(典型题)>-lt.622-循环队列 + lt.155-最小栈 + lt.232/剑指.09-栈模拟队列 + lt.225-队列模拟栈
lt.622-循环队列
[案例需求]
[思路分析]
- 详细分析查看文章: 点我
[代码实现]
class MyCircularQueue {
int rear = 0;
int front = 0;
int maxSize = 0;;
int[] arr = {};
public MyCircularQueue(int k) {
//初始化队列长度
this.maxSize = k + 1; //maxSize比k大1, 要留出一个空位作为判满的标志
arr = new int[maxSize];
}
//入队. rear
public boolean enQueue(int value) {
//入队先判满
if(this.isFull())return false;
arr[rear] = value;
rear = (rear + 1) % maxSize;
return true;
}
//出队先判空
public boolean deQueue() {
if(this.isEmpty())return false;
int data = arr[front];
front = (front + 1) % maxSize;
return true;
}
public int Front() {
if(this.isEmpty())return -1;
return arr[front % maxSize];
}
public int Rear() {
if(this.isEmpty())return -1;
return arr[(rear - 1 + maxSize) % maxSize];
}
public boolean isEmpty() {
//判空
if(rear == front) return true;
return false;
}
public boolean isFull() {
if((rear + 1) % maxSize == front) return true;
return false;
}
}
/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue obj = new MyCircularQueue(k);
* boolean param_1 = obj.enQueue(value);
* boolean param_2 = obj.deQueue();
* int param_3 = obj.Front();
* int param_4 = obj.Rear();
* boolean param_5 = obj.isEmpty();
* boolean param_6 = obj.isFull();
*/
lt.155-最小栈(同剑指.30)
[案例需求]
[思路分析]
- 最小栈, 根据题意, 往主栈中push了一堆元素, 同时不定期的pop出元素, 能够动态的返回某一时间点下的主栈中的最小值;
- 稍加思考, 我们需要一个辅助栈, 记录主栈某次操作后主栈中的最小值;
- 如何记录? 当然是在主栈入栈和出栈时,
把这个出栈或入栈的元素
和辅助栈的栈顶元素进行比较
- 辅助栈, 我们也可称之为最小栈(存储每次主栈操作后, 栈中的最小值)
-
- 主栈入栈一个元素时,
辅助栈为空
, 无条件入栈这个元素
- 主栈入栈一个元素时,
-
- 主栈入栈一个元素时,
入栈元素
<=辅助栈栈顶元素
, 主栈入栈, 辅助栈也入栈;
- 主栈入栈一个元素时,
-
- 主栈出栈一个元素时,
出栈元素
==辅助站栈顶元素
, 主栈出栈, 辅助栈也出栈;
[代码实现]
- 主栈出栈一个元素时,
class MinStack {
//设计两个栈. 一个栈存储所有元素, 另一个最小栈存储每个出栈入栈状态下的最小值
Stack<Integer> stack;
Stack<Integer> minStack;
public MinStack() {
stack = new Stack<Integer>();
minStack = new Stack<Integer>();
}
public void push(int val) {
//入栈, 对于最小栈,
//栈为空时, 入栈,
//栈顶元素 >= 入栈元素时, 也要入栈
if(minStack.size() == 0 || minStack.peek() >= val)minStack.push(val);
stack.push(val);
}
public void pop() {
//出栈, 对于最小栈
//1. 出现元素 == 栈顶元素, 也出栈
// if(stack.pop() == minStack.peek())minStack.pop();
if(stack.pop().equals(minStack.peek()))minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
lt.232 / 剑指.09-栈模拟队列
[案例需求]
[思路分析]
- 一个栈模拟队列,一个栈辅助
- 将一个栈当作输入栈,用于压入 push 传入的数据, 我们可以称之为辅助栈, 是主栈元素的一个中转站;
- 另一个栈当作输出栈,用于pop 和 peek 操作, 我们可以叫主栈, 主栈为空时, 辅助栈才能出栈到主栈
每次 pop 或 peek时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。
[代码实现]
class MyQueue {
//双栈模拟队列
/**
新元素入栈,先放入到辅助栈, 主栈为空的话, 辅助栈全部pop到主栈
主栈不为空, 那就等待辅助栈为空时再全部pop到主栈.
出栈时, 只需盯着主栈输出, 主栈没有元素了, 辅助栈出栈到主栈后继续出栈
简单来说就是主栈负责输出, 辅助栈负责输入
*/
Stack<Integer> stack1;//主栈, 输出
Stack<Integer> stack2;//辅助栈. 输入
public MyQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}
public void push(int x) {
stack2.push(x);
}
public int pop() {
if(stack1.empty()){
while(!stack2.empty()){
stack1.push(stack2.pop());
}
}
return stack1.pop();
}
public int peek() {
if(stack1.empty()){
while(!stack2.empty()){
stack1.push(stack2.pop());
}
}
return stack1.peek();
}
public boolean empty() {
// if(stack1.empty()){
// while(!stack2.empty()){
// stack1.push(stack2.pop());
// }
// }
return stack1.isEmpty() & stack2.isEmpty();
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
[时空分析]
时间复杂度:push 和 empty 为 O(1),pop 和 为均摊 O(1)。对于每个元素,至多入栈和出栈各两次,故均摊复杂度为 O(1)。
空间复杂度:O(n)。其中 n 是操作总数。对于有 n 次 push 操作的情况,队列中会有 n 个元素,故空间复杂度为 O(n)。
lt.225-队列模拟栈
[案例需求]
[思路分析]
- 用两个队列模拟实现栈
- 主队列q1, 辅助队列q2
- 当主队列q1模拟入栈时, 要把q1的元素全部出队到q2中, 然后入队, 再把q2的元素全部出队q1中
[代码实现]
class MyStack {
/**
用两个队列模拟实现栈
主队列q1, 辅助队列q2
当主队列q1模拟入栈时, 要把q1的元素全部出队到q2中, 然后入队, 再把q2的元素全部出队q1中
*/
Queue<Integer> q1;
Queue<Integer> q2;
public MyStack() {
//初始化两个队列
//使用LinkedList,
q1 = new LinkedList<Integer>();
q2 = new LinkedList<Integer>();
}
///
// q1和q2不是固定的主和辅的关系
public void push(int x) {
q2.offer(x);
while(!q1.isEmpty()){
q2.offer(q1.poll());
}
//把q2变为q1, 给q1穿上q2的衣服
Queue<Integer> temp = q1;
q1 = q2;
q2 = temp;
}
public int pop() {
return q1.poll();
}
public int top() {
return q1.peek();
}
public boolean empty() {
if(q1.isEmpty())return true;
return false;
}
}
/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* boolean param_4 = obj.empty();
*/
[时空分析]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)