做今天题目之前,可以先了解一下栈与队列理论基础
栈是先进后出,队列是先进先出
题目链接: 232.用栈实现队列
题目:
使用栈实现队列的下列操作:
push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。
思路: 第一次接触到题没啥思路,先看卡老师视频
可以通过设置两个栈来实现队列,一个进栈一个出栈,将进栈的所有元素同时移动到出栈就能实现队列的先进先出了,注意⚠️:必须是所有元素同时移动到出栈,如果部分移动,出栈元素的顺序会乱掉!
代码如下:
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
public MyQueue() {
stackIn=new Stack<>(); //负责进栈
stackOut=new Stack<>(); //负责出栈
}
//把元素 x 推到队列的末尾
public void push(int x) {
stackIn.push(x);
}
//移除队列开头元素并返回该元素,函数体里面调用的方法都是栈里面包含的,最后实现的功能是队列里的方法
public int pop() {
dumpstackIn();
return stackOut.pop();
}
//返回队列开头的元素
public int peek() {
dumpstackIn();
return stackOut.peek(); //栈里面也有返回栈顶元素的peek函数,直接用就行
}
//判断是否为空
public boolean empty() {
return stackIn.isEmpty()&&stackOut.isEmpty();
}
//如果stackOut为空,那么将stackIn中的元素全部放到stackOut中
private void dumpstackIn(){
// 必须得out里面没有元素了才能导进去,如果有元素就提前用pop方法将元素都弹出去,因为要优先使用out内的元素,如果out不为空就导进去了,元素出去的顺序就乱了
if(!stackOut.isEmpty()) return;
//循环里的条件不能写成是是否判断出栈为空,因为执行循环的时候,先把入栈里的一个元素pop出来再push进出栈,那么此时出栈就不为空了,入栈剩下的元素就不会再执行循环了
while(!stackIn.isEmpty()){
stackOut.push(stackIn.pop());
}
}
}
/**
* 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和peek为O(n)
- 空间复杂度: O(n)
题目链接:225. 用队列实现栈
题目:
使用队列实现栈的下列操作:
push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空
思路:
刚刚做过栈与队列:我用栈来实现队列怎么样? (opens new window)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行!队列模拟栈,其实一个队列就够了,那么我们先说一说两个队列来实现栈的思路。
队列是先进先出的规则,把一个队列中的数据导入另一个队列中,数据的顺序并没有变,并没有变成先进后出的顺序。所以用栈实现队列, 和用队列实现栈的思路还是不一样的,这取决于这两个数据结构的性质。但是依然还是要用两个队列来模拟栈,只不过没有输入和输出的关系,而是另一个队列完全用来备份的!把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1。这和通过1个队列的做题思路基本一致,1个队列只不过是把除了最后面的元素之外的其余元素重新导入到这个队列中去。
用1个队列做题代码如下:
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue=new LinkedList<>();
}
public void push(int x) {
queue.add(x);
}
public int pop() {
rePosition();
return queue.poll(); //poll()方法是Queue接口中定义的一个方法,它用于从队列的头部删除并返回一个元素
}
public int top() {
rePosition();
int result=queue.poll(); //此时queue就剩下最后一个元素了,因为队列里面没有栈里面返回栈顶元素的peek函数,所以为了得到这个元素需要间接通过poll方法,poll()方法它用于从队列的头部删除并返回一个元素
queue.add(result); //再把刚刚通过poll删除的元素重新添加进去
return result; //返回那个元素
}
public boolean empty() {
return queue.isEmpty();
}
public void rePosition(){
int size=queue.size();
size--; //将除了尾元素以外的其它元素全部重新导入到这个队列中去
while(size-->0){
queue.add(queue.poll()); //poll()方法是Queue接口中定义的一个方法,它用于从队列的头部删除并返回一个元素
}
}
}
/**
* 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();
*/
- 时间复杂度: push为O(n),其他为O(1)
- 空间复杂度: O(n)