于2021.11.28记录
接着上一篇关于栈和队列的博文栈和队列题目记录(一)
232. 用栈实现队列
思路:这道题目是一道模拟题,考察对栈和队列的理解。
因为栈是FILO(只能在栈顶进入和弹出),而队列是FIFO(在队头出队,在队尾入队),因此想要用栈来实现队列,就需要用到两个栈:输入栈stIn和输出栈stOut。
(1)队列的push操作
直接让输入栈做入栈操作即可。
(2)队列的pop操作
判断输出栈是否为空:如果不为空,那么直接将输出栈中的元素弹出即可;如果为空,要将输入栈中的元素弹出在放入到输出栈中,此时原输入栈中栈底元素变为了输出栈中的栈顶元素,一直执行此操作,直到输入栈为空,那么此时输入栈中的元素就全部搬运到了输出栈中,此时将输出栈中的元素弹出即为队列的出队元素。
(3)队列的peek操作
和pop的思想相同
判断输出栈是否为空:如果不为空,那么输出栈的栈顶元素即为结果;如果为空,将输入栈中的元素全部搬运到输出栈中,此时原输入栈中栈底元素变栈顶,然后此时的栈顶即为结果。
(4)队列的empty操作
当输入栈和输出栈均为空时,队列才为空。
class MyQueue {
Stack<Integer> stIn;
Stack<Integer> stOut;
public MyQueue() {
stIn = new Stack<>();
stOut = new Stack<>();
}
public void push(int x) {
stIn.push(x);
}
public int pop() {
if(stOut.empty()){
while(!stIn.empty()){
stOut.push(stIn.pop());
}
}
return stOut.pop();
}
public int peek() {
if(stOut.empty()){
while(!stIn.empty()){
stOut.push(stIn.pop());
}
}
return stOut.peek();
}
public boolean empty() {
return stIn.empty() && stOut.empty();
}
}
/**
* 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();
*/
思考:由于队列先进先出,而栈先入后出,所以先进来的元素送入栈中会置于栈底,如果要将其出队,那么就需要有一个中介,将原来位于栈底的变到栈顶,然后在出队就正确了。
225. 用队列实现栈
1.1 解法1:单个队列实现
思路:由于栈是先入后出,而队列是先入先出,因此使用一个队列实现栈时,需要保证队列前端的元素是最后入栈的元素。
(1)栈的push操作
如果不做任何处理,那么队列中存放元素的顺序和栈中存放元素的顺序应该是刚好反着的,即栈底的元素对应队列的前端,栈顶的元素对应队列的尾部。
入栈操作时,首先获取此时队列中元素的个数n,然后将该元素入队到队列,再将队列中前端的n个元素(除了新入栈元素的其他所有元素)依次出队并入队到队列,此时队列前端的元素就是新入栈的元素了,且此时队列中存放的顺序就和栈中的顺序相同了,即栈底的元素对应队列的尾部,栈顶的元素对应队列的头部。
类似于把队列想象成一个环,将前面的元素,通过环路,都转移到后面来。
(2)栈的pop操作
由于队列和栈的顺序相同,那么直接让队列出队即可。
(3)栈的top操作
由于队列和栈的顺序相同,那么直接返回队列的前端元素。
(4)栈的empty操作
只需判断队列是否为空即可。
class MyStack {
Queue<Integer> que;
public MyStack() {
que = new LinkedList<>();
}
public void push(int x) {
int n = que.size();
que.offer(x);
for(int i = 0;i < n;i++){
que.offer(que.poll());
}
}
public int pop() {
return que.poll();
}
public int top() {
return que.peek();
}
public boolean empty() {
return que.isEmpty();
}
}
/**
* 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();
*/
思考:用队实现栈,每次入栈后,栈顶的元素都放在了队列的最后面,因此将队列中该元素前面的所有元素出队在入队,就把该元素放在了队列的前端。相当于把队列看成一个环,把前面的元素都通过环链接到后面去。
1.2 解法2:两个队列实现
思路:定义两个队列,其中que1表示和栈中元素顺序一致的队列,que2表示辅助队列。
入栈时,首先将元素入队到que2,然后将que1中的全部元素依次出队并入队到que2中,此时que2中前端的元素即为新入栈的元素,再将que1和que2互换,那么que1中的元素即为栈内的元素,队列的前端和后端分别对应栈顶和栈底。
que2其实一直都属于空的状态,它的目的就是为了放进去一个新元素,然后把que1的元素放入到que2队列中,使得后入栈的元素在最前面,然后再交换que1和que2,这时候que2就又为空了。
class MyStack {
Queue<Integer> que1;
Queue<Integer> que2;
public MyStack() {
que1 = new LinkedList<>();
que2 = new LinkedList<>();
}
public void push(int x) {
que2.offer(x);
while(!que1.isEmpty()){
que2.offer(que1.poll());
}
Queue<Integer> tmp = new LinkedList<>();
tmp = que1;
que1 = que2;
que2 = tmp;
}
public int pop() {
return que1.poll();
}
public int top() {
return que1.peek();
}
public boolean empty() {
return que1.isEmpty();
}
}
/**
* 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();
*/
思考:用两个队列实现栈,其实第一个队列一直存放的都是和栈中元素顺序一致的元素,第二个队列一开始先用于存放新入栈的元素,然后在将第一个队列中的元素进入到第二个队列,此时第二个队列中显然存放了和栈中顺序一致的元素,然后两个队列交换。这样就可以保证新入栈的元素在队列的最前面。