20, 225. 用队列实现栈
https://leetcode-cn.com/problems/implement-stack-using-queues/
思路1: 通过两个队列实现
- 队列是先进先出
- 栈是先进后出。
- 通过两个先进先出的队列,实现一个先进后出的栈。具体如下
- 入栈的时候,先把resuleQueue的数据出对,然后入队到tmpQueue
- 然后把需要入栈的数据入队到resuleQueue
- 然后再把tmpQueue出对,然后入对到resuleQueue
- 然后出栈的时候,直接resuleQueue出对,就能保证:最后入队的可以优先出对
package com.shangguigu.dachang.algrithm.A07_queue_and_stack;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author : 不二
* @date : 2022/4/16-上午7:59
* @desc : 225. 用队列实现栈
* https://leetcode-cn.com/problems/implement-stack-using-queues/
* 其实在队列中有一种双端队列,两端都是可以删除和追加数据,可以直接实现队列的作用
* 不过在题目中要求要自己通过队列实现栈,而不能直接抄现成的
*
* 我们这里自己实现
*
*
**/
public class A67_stack_by_queue_v1_custom_v1 {
public static void main(String[] args) {
A67_stack_by_queue_v1_custom_v1 myStack = new A67_stack_by_queue_v1_custom_v1();
myStack.push(1);
myStack.push(2);
System.out.println(myStack.top());; // 返回 2
System.out.println(myStack.pop());; // 返回 2
System.out.println(myStack.empty());; // 返回 False
}
// 构造方法
public A67_stack_by_queue_v1_custom_v1() {
// 容量可变,ArrayQueue则容量是固定的
resuleQueue = new LinkedList<>();
tmpQueue = new LinkedList<>();
}
// 队列是先进先出
// 栈是先进后出。
// 通过两个先进先出的队列,实现一个先进后出的栈。具体如下
// 入栈的时候,先把resuleQueue的数据出对,然后入队到tmpQueue
// 然后出栈的时候,直接resuleQueue出对,就能保证:最后入队的可以优先出对
Queue<Integer> resuleQueue;
Queue<Integer> tmpQueue;
// 入栈的时候,先把resuleQueue的数据出对,然后入队到tmpQueue
public void push(int x) {
// 先把resuleQueue的数据全部出对,然后入队到tmpQueue;
while (resuleQueue.peek() != null) {
tmpQueue.offer(resuleQueue.poll());
}
// 然后把新push的数据入队到resuleQueue
resuleQueue.offer(x);
// 最后把tmpQueue的数据回对到resuleQueue
while (tmpQueue.peek() != null) {
resuleQueue.offer(tmpQueue.poll());
}
}
// 返回最顶端的数据
public int top() {
Integer peek = resuleQueue.peek();
if (peek == null) {
return -1;
} else {
return peek;
}
}
public int pop(){
Integer poll = resuleQueue.poll();
if (poll != null) {
return poll;
} else {
return -1;
}
}
public boolean empty(){
return resuleQueue.isEmpty();
}
}
思路2: 通过两个队列实现优化
思路1中:
- resuleQueue -> tmpQueue
- x -> resuleQueue
- tmpQueue -> resuleQueue 这种流程会有两轮数据交换。其实我们可以直接通过互换指针省去第二轮到数据交换
具体做法如下:
- x -> tmpQueue
- resuleQueue -> tmpQueue,这时tmpQueue就是最终结果
- tmpQueue和resuleQueue互换即可
package com.shangguigu.dachang.algrithm.A07_queue_and_stack;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author : 不二
* @date : 2022/4/16-上午7:59
* @desc : 225. 用队列实现栈
* https://leetcode-cn.com/problems/implement-stack-using-queues/
* 其实在队列中有一种双端队列,两端都是可以删除和追加数据,可以直接实现队列的作用
* 不过在题目中要求要自己通过队列实现栈,而不能直接抄现成的
*
* 我们这里自己实现
* 在v1的版本中:先把resuleQueue放入到tmpQueue
* 然后把入队数据放入resuleQueue
* 最后把tmpQueue再放回到resuleQueue
* 这么做有一个很大到问题:交换到数据太多了
* 这里可以这么优化一下:
* 入队到时候直接入队到tmpQueue
* 然后把resuleQuue放入到tmpQueue
* 然后把tmpQueue和resuleQueue直接交换即可
* 这样的话,指针交换就一步, 节省了第二遍队列的出入队
*
**/
public class A67_stack_by_queue_v1_custom_v2 {
public static void main(String[] args) {
A67_stack_by_queue_v1_custom_v2 myStack = new A67_stack_by_queue_v1_custom_v2();
myStack.push(1);
myStack.push(2);
System.out.println(myStack.top());; // 返回 2
System.out.println(myStack.pop());; // 返回 2
System.out.println(myStack.empty());; // 返回 False
}
// 构造方法
public A67_stack_by_queue_v1_custom_v2() {
// 容量可变,ArrayQueue则容量是固定的
resuleQueue = new LinkedList<>();
tmpQueue = new LinkedList<>();
}
// 队列是先进先出
// 栈是先进后出。
// 通过两个先进先出的队列,实现一个先进后出的栈。具体如下
// 入栈的时候,先入队到tmpQueue,然后把resuleQueue的数据入队到tmpQueue,然后resuleQueue和tmpQueue互换即可
// 然后出栈的时候,直接resuleQueue出对,就能保证:最后入队的可以优先出对
Queue<Integer> resuleQueue;
Queue<Integer> tmpQueue;
// 入栈的时候,先把resuleQueue的数据出对,然后入队到tmpQueue
public void push(int x) {
// 先把数据入队到tmpQueue
tmpQueue.offer(x);
// 然后把resuleQueue入队到tmpQueue中
while (resuleQueue.peek() != null) {
tmpQueue.offer(resuleQueue.poll());
}
// 最后把resuleQueue和tmpQueue互换即可
Queue<Integer> theQueue = tmpQueue;
tmpQueue = resuleQueue;
resuleQueue = theQueue;
}
// 返回最顶端的数据
public int top() {
Integer peek = resuleQueue.peek();
if (peek == null) {
return -1;
} else {
return peek;
}
}
public int pop(){
Integer poll = resuleQueue.poll();
if (poll != null) {
return poll;
} else {
return -1;
}
}
public boolean empty(){
return resuleQueue.isEmpty();
}
}
思路3: 直接通过一个队列实现
- 思路1和思路2都是通过两个队列交换实现
- 但是实际上,我们可以通过一个队列:先入队x,然后把x在队列中之前的数据重新出对再入队就可以实现数据逆转
package com.shangguigu.dachang.algrithm.A07_queue_and_stack;
import java.util.LinkedList;
import java.util.Queue;
/**
* @author : 不二
* @date : 2022/4/16-上午7:59
* @desc : 225. 用队列实现栈
* https://leetcode-cn.com/problems/implement-stack-using-queues/
* 其实在队列中有一种双端队列,两端都是可以删除和追加数据,可以直接实现队列的作用
* 不过在题目中要求要自己通过队列实现栈,而不能直接抄现成的
*
* 我们这里自己实现
* 在v1的版本中:先把resuleQueue放入到tmpQueue
* 然后把入队数据放入resuleQueue
* 最后把tmpQueue再放回到resuleQueue
* 这么做有一个很大到问题:交换到数据太多了
* 可以这么优化一下:
* 入队到时候直接入队到tmpQueue
* 然后把resuleQuue放入到tmpQueue
* 然后把tmpQueue和resuleQueue直接交换即可
* 这样的话,指针交换就一步, 节省了第二遍队列的出入队
*
* 不过v1的时候依然是使用两个队列的
* 我们这里其实可以直接使用一个队列:入队一个数据的时候,我们把这个数据之前的数据重新出对,再入队就能实现
* 如果按照这种方式,我们需要一个size来判定到底哪些数据需要重新出对入对
*
*
**/
public class A68_stack_by_queue_v2 {
public static void main(String[] args) {
A68_stack_by_queue_v2 myStack = new A68_stack_by_queue_v2();
myStack.push(1);
myStack.push(2);
System.out.println(myStack.top());; // 返回 2
System.out.println(myStack.pop());; // 返回 2
System.out.println(myStack.empty());; // 返回 False
}
// 构造方法
public A68_stack_by_queue_v2() {
// 容量可变,ArrayQueue则容量是固定的
resuleQueue = new LinkedList<>();
// tmpQueue = new LinkedList<>();
// size = 0;
}
// 队列是先进先出
// 栈是先进后出。
Queue<Integer> resuleQueue;
// Queue<Integer> tmpQueue;
// int size;
// 入栈对时候,把当前数据的其他数据重新出栈入栈,就能保证数据逆转
public void push(int x) {
// 数量先加
// size++;
// 然后数据先放入队列
resuleQueue.offer(x);
// 如果队列个数大于2
if (resuleQueue.size() >= 2) {
// 最后一个不需要重新出入对哈
for (int i = 0; i < resuleQueue.size() - 1; i++) {
resuleQueue.offer(resuleQueue.poll());
}
}
}
// 返回最顶端的数据
public int top() {
Integer peek = resuleQueue.peek();
if (peek == null) {
return -1;
} else {
return peek;
}
}
public int pop(){
Integer poll = resuleQueue.poll();
// size--;
if (poll != null) {
return poll;
} else {
return -1;
}
}
public boolean empty(){
return resuleQueue.isEmpty();
}
}