栈和队列
一、栈的典型应用
*1、有效的括号(20)
//思路:
//(1)是左方向的括号,就直接入栈
//(2)右方向的括号,就拿出栈顶元素与之对比,匹配就弹出
public boolean isValid(String s) {
//注意空字符串可被认为是有效字符串。
if(s==null || s.length()==0){
return true;
}
Stack stack = new Stack<>();
//将 s 转换为字符数组,方便后面对字符的操作
char[] ss = s.toCharArray();
for(Character c : ss){
//如果当前的字符串是左方向的字符串则直接入栈
if(c == '(' || c =='[' || c=='{'){
stack.push(c);
}else{
//没有左方向的括号且s不为null,显然不匹配的
if(stack.isEmpty()){
return false;
}
// topc 记录的是栈顶的元素
char topc = stack.peek();
if((topc=='(' && c==')') ||
(topc=='[' && c==']')||
(topc=='{' && c=='}')) {
stack.pop();
}else{
return false;
}
}
}
// stack 如果是空的,则完全匹配,返回true
return stack.isEmpty();
}
@Test
public void test(){
//String s="()";
//String s="()[]{}";
//String s="(]";
String s="([)]";
//String s="{[]}";
System.out.println(isValid(s));
}
*2、逆波兰表达式求值(150)
public int evalRPN(String[] tokens) {
Stack stack = new Stack<>();
for(String token:tokens){
switch (token){
case "+": {
int num1 = stack.pop();
int num2 = stack.pop();
stack.push(num2+num1);
break;
}
case "-":{
int num1 = stack.pop();
int num2 = stack.pop();
stack.push(num2-num1);
break;
}
case "*":{
int num1 = stack.pop();
int num2 = stack.pop();
stack.push(num2*num1);
break;
}
case "/":{
int num1 = stack.pop();
int num2 = stack.pop();
stack.push(num2/num1);
break;
}
default:{
int num = Integer.parseInt(token);
stack.push(num);
break;
}
}
}
return stack.pop();
}
@Test
public void test(){
//String[] tokens = {"2", "1", "+", "3", "*"};
//String[] tokens = {"4", "13", "5", "/", "+"};
String[] tokens = {"10", "6", "9", "3", "+","-11", "*","/", "*","17", "+", "5", "+"};
System.out.println(evalRPN(tokens));
}
3、简化路径(71)
/**
* 思路:
* 1、会出现几中字符:
* /
* .
* ..
* 这三种字符;
* 2、字符串处理,由于".."是返回上级目录(如果是根目录则不处理),
* 因此可以考虑用栈记录路径名,以便于处理。
*
* 需要注意几个细节:
* 1、何时出栈?
* "../ "代表回上一级目录,此时栈顶元素出栈,表示返回上一级
*
* 2、何时
* 如果遇到不是 ".",也不是"",不是"..",那么进栈
* "" 针对的是 // 这种情况。
*/
public String simplifyPath(String path) {
if(path==null){
return "/";
}
//根据 / 来切分目录
String[] dirs = path.split("/");
Stack stack = new Stack<>();
for(String dir : dirs){
if("..".equals(dir)){
if(!stack.isEmpty()){
stack.pop();
}
}
if(!".".equals(dir) && !"".equals(dir) && !"..".equals(dir)){
stack.push(dir);
}
}
return "/"+String.join("/",stack);
}
@Test
public void test(){
//String path = "/home/";
//String path = "/../";
//String path="/home//foo/";
String path ="/a/../../b/../c//.//";
System.out.println(simplifyPath(path));
}
4、 行星碰撞(735)
public int[] asteroidCollision(int[] asteroids) {
if(asteroids==null || asteroids.length==0){
return new int[]{};
}
if(asteroids.length==1){
return new int[]{asteroids[0]};
}
Stack stack = new Stack<>();
for(int asteroid : asteroids){
if(stack.isEmpty() || asteroid>0){
stack.push(asteroid);
continue; //直接进入下一次循环
}
//处理 asteroid < 0 的情况
while (true){
int top = stack.peek();
if(top<0){ //相同方向,则直接入栈
stack.push(asteroid);
break;
}
// top > 0
if(top == -asteroid){ //相撞后,栈顶的是要消失的
stack.pop();
break;
}else if(top > -asteroid){ // top 质量更大,则 asteroid 不能入栈
break;
}else{
assert top < -asteroid;
// 需要出栈
stack.pop();
if(stack.isEmpty()){ //栈内的都被碰撞完了,则剩下该行星了
stack.push(asteroid);
break;
}
}
}
}
int[] res = new int[stack.size()];
//注意:stack 出栈的顺序和数组原来的顺序是相反的
int index=stack.size()-1;
while(!stack.isEmpty()){
res[index--] = stack.pop();
}
return res;
}
@Test
public void test(){
//int[] asteroids = {5, 10, -5};
//int[] asteroids = {8, -8};
//int[] asteroids = {10, 2, -5};
//int[] asteroids = {-2, -1, 1, 2};
int[] asteroids ={-2,-2,1,-2};
int[] res = asteroidCollision(asteroids);
for(int num : res){
System.out.println(num);
}
}
二、运用栈模拟递归
1、二叉树的前序遍历(144)
//采用枚举类型,GO 表示访问节点,PRINT 表示要打印该节点
private enum Command{Go,Print};
private class StackNode{
TreeNode node;
Command command;
StackNode(TreeNode node,Command command){
this.node = node;
this.command = command;
}
}
public List preorderTraversal(TreeNode root) {
List res = new ArrayList<>();
if(root==null){
return res;
}
Stack stack = new Stack<>();
stack.push(new StackNode(root,Command.Go));
while(!stack.isEmpty()){
StackNode node = stack.pop();
TreeNode treeNode = node.node;
Command command = node.command;
if(command.equals(Command.Print)){
res.add(treeNode.val);
}else{
if(treeNode.right!=null){
stack.push(new StackNode(treeNode.right,Command.Go));
}
if(treeNode.left!=null){
stack.push(new StackNode(treeNode.left,Command.Go));
}
stack.push(new StackNode(treeNode,Command.Print));
}
}
return res;
}
@Test
public void test(){
int[] pre={4,9,5,1,0};
int[] in={5,9,1,4,0};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre,in);
System.out.println(preorderTraversal(root));
}
2、二叉树的中序遍历(94)
private enum Command{Go,Print};
private class StackNode{
TreeNode node;
Command command;
StackNode(TreeNode node,Command command){
this.node = node;
this.command = command;
}
}
public List inorderTraversal(TreeNode root) {
List res = new ArrayList<>();
if(root==null){
return res;
}
Stack stack=new Stack<>();
stack.push(new StackNode(root,Command.Go));
while(!stack.isEmpty()){
StackNode node = stack.pop();
TreeNode treeNode = node.node;
Command command = node.command;
if(command.equals(Command.Print)){ //只有遇到打印命令时,才可打印
res.add(treeNode.val);
}else{
if(treeNode.right!=null){
stack.push(new StackNode(treeNode.right,Command.Go));
}
stack.push(new StackNode(treeNode,Command.Print));
if(treeNode.left!=null){
stack.push(new StackNode(treeNode.left,Command.Go));
}
}
}
return res;
}
@Test
public void test(){
int[] pre={4,9,5,1,0};
int[] in={5,9,1,4,0};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre,in);
System.out.println(inorderTraversal(root));
}
3、二叉树的后序遍历(145)
private enum Command{Go,Print};
private class StackNode{
TreeNode node;
Command command;
StackNode(TreeNode node,Command command){
this.node = node;
this.command = command;
}
}
public List postorderTraversal(TreeNode root) {
List res = new ArrayList<>();
if(root==null){
return res;
}
Stack stack = new Stack<>();
stack.push(new StackNode(root,Command.Go));
while(!stack.isEmpty()){
StackNode node = stack.pop();
TreeNode treeNode = node.node;
Command command = node.command;
if(command.equals(Command.Print)){
res.add(treeNode.val);
}else{
stack.push(new StackNode(treeNode,Command.Print));
if(treeNode.right!=null){
stack.push(new StackNode(treeNode.right,Command.Go));
}
if(treeNode.left!=null){
stack.push(new StackNode(treeNode.left,Command.Go));
}
}
}
return res;
}
@Test
public void test(){
int[] pre={4,9,5,1,0};
int[] in={5,9,1,4,0};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre,in);
System.out.println(postorderTraversal(root));
}
三、队列的典型应用
*1、二叉树的层次遍历(102)
import javafx.util.Pair;
//思路:
//1、队列一般用来进行二叉树的层次遍历
//2、这里要注意创建新的 ArrayList 的时机
public List> levelOrder(TreeNode root) {
List> res = new ArrayList<>();
if(root ==null){
return res;
}
// queue 存储是树的节点及该节点对应的层数
Queue> queue = new LinkedList<>();
// root 根节点从 0 层开始,方便后面的操作,因为 List 下标也是从 0 开始的
queue.add(new Pair<>(root,0));
res.add(new ArrayList<>(root.val));
while(!queue.isEmpty()){
Pair pair = queue.poll();
TreeNode node = pair.getKey();
Integer level = pair.getValue();
if(level == res.size()){ // 从第 0 层开始遍历
//TODO:此时创建新的 ArrayList
res.add(new ArrayList<>());
}
//node.val 是 level 层数据
res.get(level).add(node.val);
//对 level+1 层的数据进行处理
if(node.left != null){
queue.add(new Pair<>(node.left,level+1));
}
if(node.right!= null){
queue.add(new Pair<>(node.right,level+1));
}
}
return res;
}
@Test
public void test(){
int[] pre ={3,9,20,15,7};
int[] in ={9,3,15,20,7};
List> res= levelOrder(
TreeNodeUtils.ConstructBinaryTree(pre,in));
for(List list : res){
System.out.println(list);
}
}
思路二:队列存储的每层次的结点。
//思路二:
public List> levelOrder(TreeNode root) {
List> res = new ArrayList<>();
if(root ==null){
return res;
}
Queue queue = new LinkedList<>();
queue.add(root);
int level=0;
while(!queue.isEmpty()){
int num = queue.size();
res.add(new ArrayList<>());
while(num>0){
TreeNode node = queue.poll();
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
res.get(level).add(node.val);
num--;
}
level++;
}
return res;
}
@Test
public void test(){
int[] pre ={3,9,20,15,7};
int[] in ={9,3,15,20,7};
List> res= levelOrder(
TreeNodeUtils.ConstructBinaryTree(pre,in));
for(List list : res){
System.out.println(list);
}
}
2、二叉树的层次遍历 II(107)
//思路:与 102 题一样
//注意:使用 Collections.revers(res) --> 反向输出 res 结果即可
public List> levelOrderBottom(TreeNode root) {
List> res = new ArrayList<>();
if(root==null){
return res;
}
// queue 存储是树的节点及该节点对应的层数
Queue> queue = new LinkedList<>();
queue.add(new Pair<>(root,0));
while (!queue.isEmpty()){
Pair pair = queue.poll();
TreeNode node = pair.getKey();
int level = pair.getValue();
if(level==res.size()){
res.add(new ArrayList<>());
}
res.get(level).add(node.val);
if(node.left!=null){
queue.add(new Pair<>(node.left,level+1));
}
if(node.right!=null){
queue.add(new Pair<>(node.right,level+1));
}
}
Collections.reverse(res);
return res;
}
@Test
public void test(){
int[] pre={3,9,20,15,7};
int[] in={9,3,15,20,7};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre, in);
List> res = levelOrderBottom(root);
System.out.println(res);
}
//思路二:
//队列只存储每层的节点
public List> levelOrderBottom(TreeNode root) {
List> res = new ArrayList<>();
if(root==null){
return res;
}
Queue queue = new LinkedList<>();
queue.add(root);
int level=0;
while(!queue.isEmpty()){
int num = queue.size();
res.add(new ArrayList<>());
while(num>0){
TreeNode node = queue.poll();
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
res.get(level).add(node.val);
num--;
}
level++;
}
Collections.reverse(res);
return res;
}
@Test
public void test(){
int[] pre={3,9,20,15,7};
int[] in={9,3,15,20,7};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre, in);
List> res = levelOrderBottom(root);
System.out.println(res);
}
3、二叉树的锯齿形层次遍历(103)
public List> zigzagLevelOrder(TreeNode root) {
List> res = new ArrayList<>();
if(root==null){
return res;
}
//注意:是每个顶点对应一个层次
Queue> queue = new LinkedList<>();
queue.add(new Pair<>(root,0));
while(!queue.isEmpty()){
Pair pair = queue.poll();
TreeNode node = pair.getKey();
int level = pair.getValue();
if(level == res.size()){
res.add(new ArrayList<>());
}
res.get(level).add(node.val);
if(node.left!=null){
queue.add(new Pair<>(node.left,level+1));
}
if(node.right!=null){
queue.add(new Pair<>(node.right,level+1));
}
}
int level = 1;
for(List list : res){
if(level%2==0){ //偶数层就反转
Collections.reverse(list);
}
level++;
}
return res;
}
@Test
public void test(){
int[] pre={3,9,20,15,7};
int[] in={9,3,15,20,7};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre, in);
List> res = zigzagLevelOrder(root);
System.out.println(res);
}
//思路二:
//队列只存储每层的节点
public List> zigzagLevelOrder(TreeNode root) {
List> res = new ArrayList<>();
if(root==null){
return res;
}
//使用 queue 存储的是每层的节点
Queue queue=new LinkedList<>();
queue.add(root);
int level = 0; //当前层数,为了方便list添加,这里从 0 开始
while (!queue.isEmpty()){
int num = queue.size(); //该层的节点数
res.add(new ArrayList<>());
while(num>0){
TreeNode node = queue.poll();
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
res.get(level).add(node.val);
num--;
}
if(level%2==1){
Collections.reverse(res.get(level));
}
level++;
}
return res;
}
@Test
public void test(){
int[] pre={3,9,20,15,7};
int[] in={9,3,15,20,7};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre, in);
List> res = zigzagLevelOrder(root);
System.out.println(res);
}
4、二叉树的右视图(199)
//思路一:暴力解法
public List rightSideView(TreeNode root) {
List res = new ArrayList<>();
if(root==null){
return res;
}
//存储该二叉树进行层次遍历的结果
List> levelOrder = new ArrayList<>();
Queue> queue = new LinkedList<>();
queue.add(new Pair<>(root,0));
while(!queue.isEmpty()){
Pair pair = queue.poll();
TreeNode node = pair.getKey();
int level = pair.getValue();
if(level == levelOrder.size()){
levelOrder.add(new ArrayList<>());
}
levelOrder.get(level).add(node.val);
if(node.left!=null){
queue.add(new Pair<>(node.left,level+1));
}
if(node.right!=null){
queue.add(new Pair<>(node.right,level+1));
}
}
System.out.println(levelOrder);
for(List list : levelOrder){
int lastIndex = list.size()-1;
res.add(list.get(lastIndex));
}
return res;
}
@Test
public void test(){
int[] pre={1,2,5,3,4};
int[] in={2,5,1,3,4};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre,in);
System.out.println(rightSideView(root));
}
//思路二:
//队列只存储每层的节点
public List rightSideView(TreeNode root) {
List res = new ArrayList<>();
if(root==null){
return res;
}
//使用 queue 存储某一层的节点
Queue queue = new LinkedList<>();
queue.add(root); //第一层只有一个 root 结点
while(!queue.isEmpty()){
int num = queue.size();//该层的节点数
while(num>0){ //遍历节点
TreeNode node = queue.poll();
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
num--;
if(num==0){ //遍历到最后一个元素,其实就是右边的节点
res.add(node.val);
}
}
//经过循环后,queue 此时该层的所有的节点出队,存储的是下一层的节点
}
return res;
}
@Test
public void test(){
int[] pre={1,2,5,3,4};
int[] in={2,5,1,3,4};
TreeNode root = TreeNodeUtils.ConstructBinaryTree(pre,in);
System.out.println(rightSideView(root));
}
四、BFS 和队列
*1、完全平方数(279)
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
// 思路:
// 1、贪心算法?
// 使用贪心策略:每次取最大的完全平方数,则12 = 9+1+1+1,但是12 = 4+4+4是最终解。
// 2、对问题建模:将整个问题转化为图论问题。
// 从 n 到 0,每个数字表示一个节点;
// 如果两个数字 x 到 y 相差一个完全平方数,则连接一条边。我们就得到了整个无权图。
// 那么,原来的问题就转化成,求这个无权图中从n到0的最短路径。
n = 4 时,对应的无权图。
- n = 5 时,对应的无权图。
n = 6 时,对应的无权图。
// 由无权图的性质,最短路径通过 BFS 可以得到。
public int numSquares(int n) {
Queue queue = new LinkedList<>();
queue.add(new Vertex(n,0));
//优化效率: 已经访问过的顶点不能再访问了
boolean[] visited = new boolean[n+1];
visited[n] = true;
while(!queue.isEmpty()){
Vertex vertex = queue.poll();
int num = vertex.num;
int steps = vertex.steps;
if(num == 0){ //已经到达 0 位置了
return steps;
}
for(int i=1;;i++){
int tmp = num - i*i;
if(tmp<0){
break;
}
if(!visited[tmp]){
queue.add(new Vertex(tmp,steps+1));
visited[tmp] = true;
}
}
}
return 0;
}
private class Vertex { //表示该无权图的顶点
int num;
int steps; //记录到 num 的步数。num = n 时,steps=0
public Vertex(int num,int steps){
this.num = num;
this.steps = steps;
}
}
2、单词接龙(127)
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
输出: 5
解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
返回它的长度 5。
示例 2:
输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
输出: 0
解释: endWord "cog" 不在字典中,所以无法进行转换。
//思路:将单词看成图的顶点
// word1-->word2 的路径就是word1 和 word2 "相似"(word1和wordd2根据题目规则可以相互转化)
// 最后从 beginWord 走到 endWord。示例 1 可表示成如下无权图:
public int ladderLength(String beginWord, String endWord, List wordList) {
//优化:提高效率
Set wordSet = new HashSet<>();
for(String word : wordList){
wordSet.add(word);
}
//存储已经被访问的 word
Set visited = new HashSet<>();
Queue queue = new LinkedList<>();
queue.add(new Vertex(beginWord,1));
while(!queue.isEmpty()){
Vertex vertex = queue.poll();
String curWord = vertex.word;
int steps = vertex.steps;
visited.clear();
if(endWord.equals(curWord)){
return steps;
}
for(String word : wordSet){
if(isSimilar(word,curWord)){
queue.add(new Vertex(word,steps+1));
visited.add(word);
}
}
for(String w : visited){
wordSet.remove(w);
}
}
return 0;
}
//判断 word1 和 word2 是否相似,即 word1 和 word2 是否可以相互转化
private boolean isSimilar(String word1,String word2){
if(word1.length()!=word2.length() || word1.equals(word2)){
return false;
}
int diff=0;
for(int i=0;i
if(word1.charAt(i)!=word2.charAt(i)){
diff++;
}
if(diff>1){ //要求 word1 和 word2 中只有一个字符是不同的
return false;
}
}
return true;
}
private class Vertex{
String word;
int steps; //记录到 word 的步数
public Vertex(String word,int steps){
this.word = word;
this.steps = steps;
}
}
五、优先队列
*1、前 K 个高频元素(347)
public List topKFrequent(int[] nums, int k) {
List res = new ArrayList<>();
if(k<0 || k>nums.length){
return res;
}
//统计数字出现次数
Map records = new HashMap<>();
for(int num : nums){
int freq = records.getOrDefault(num,0);
records.put(num,++freq);
}
NumFrequent[] numFrequents = new NumFrequent[records.size()];
int i=0;
for(int num : records.keySet()){
int freq = records.get(num);
numFrequents[i] = new NumFrequent(num,freq);
i++;
}
//默认是小根堆
PriorityQueue pq = new PriorityQueue<>(new Comparator() {
@Override
public int compare(NumFrequent o1, NumFrequent o2) {
int num = o1.freq - o2.freq; //先按照频率,进行升序排列
int num2 = (num==0)? o1.num - o2.num:num;
return num2;
}
});
for(NumFrequent numFrequent : numFrequents){
pq.add(numFrequent);
if(pq.size()>k){
pq.poll();
}
}
while(!pq.isEmpty()){
res.add(pq.poll().num);
}
return res;
}
private class NumFrequent{
int num;
int freq;
NumFrequent(int num,int freq){
this.num = num;
this.freq = freq;
}
}
2、前K个高频单词(692)
public List topKFrequent(String[] words, int k) {
List res = new ArrayList<>();
if(k<0 || k>words.length){
return res;
}
//统计数字出现次数
Map records = new HashMap<>();
for(String word : words){
int freq = records.getOrDefault(word,0);
records.put(word,++freq);
}
WordFrequent[] wordFrequents = new WordFrequent[records.size()];
int i=0;
for(String word : records.keySet()){
int freq = records.get(word);
wordFrequents[i] = new WordFrequent(word,freq);
i++;
}
//默认是小根堆
PriorityQueue pq = new PriorityQueue<>(new Comparator() {
@Override
public int compare(WordFrequent o1, WordFrequent o2) {
int num = o1.freq - o2.freq;
int num2 = (num==0)?o2.word.compareTo(o1.word):num; //注意这里要逆序,这样后面输出才是正序的
return num2;
}
});
for(WordFrequent numFrequent : wordFrequents){
pq.add(numFrequent);
if(pq.size()>k){
pq.poll();
}
}
Stack stack = new Stack<>();
while(!pq.isEmpty()){
stack.push(pq.poll().word);
}
while(!stack.isEmpty()){
res.add(stack.pop());
}
return res;
}
private class WordFrequent{
String word;
int freq;
WordFrequent(String word,int freq){
this.word = word;
this.freq = freq;
}
}
@Test
public void test(){
//String[] words={"i", "love", "leetcode", "i", "love", "coding"};
//int k = 2;
String[] words={"the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"};
int k = 4;
System.out.println(topKFrequent(words,k));
}
*六、栈和队列关系
1、用栈实现队列(232)
//思路:
//使用两个栈解决
class MyQueue {
private Stack stack1;
private Stack stack2;
//存储队列头元素
private int front; //方便后面的 peek() 操作
/** Initialize your data structure here. */
public MyQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}
/** Push element x to the back of queue. */
public void push(int x) {
if(stack1.isEmpty()){ //此时 x 是第一个元素,方便后面的 peek()操作
front = x;
}
//放入元素,优先放入 stack1 中
stack1.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
if(empty()){
throw new IllegalArgumentException("stack is empty");
}
if(stack2.isEmpty()){
//经过若干次 pop 后,stack2 有可能为空,所以需要判空处理
//stack2 中没有任何元素
//取出 stack1 中所有元素,都放入 stack2 中
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
/** Get the front element. */
public int peek() {
if(!stack2.isEmpty()){
return stack2.peek();
}
// front 是为了防止 push 后,stack2 中没有元素的情况
return front;
}
/** Returns whether the queue is empty. */
public boolean empty() { //注意两个栈都为空,才为空 -->
// 比如不断 push,则 stack1 中有元素,但 stack2 中没有元素
return (stack1.isEmpty() && stack2.isEmpty());
}
}
@Test
public void test(){
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
System.out.println(queue.peek()); // 返回 1
System.out.println(queue.pop()); // 返回 1
queue.empty(); // 返回 false
}
2、用队列实现栈(225)
class MyStack {
private Queue queue1;
private Queue queue2;
/** Initialize your data structure here. */
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
/** Push element x onto stack. */
public void push(int x) {
queue1.offer(x);
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
if(empty()){
throw new IllegalArgumentException("stack is empty");
}
while (queue1.size()>1){
queue2.offer(queue1.poll());
}
int num = queue1.poll();
//即使出栈后,交换两个队列,始终保持 queue1 队列中存在元素
Queue tmp = queue1;
queue1 = queue2;
queue2 = tmp;
return num;
}
/** Get the top element. */
public int top() {
while (queue1.size()>1){
queue2.offer(queue1.poll());
}
return queue1.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return (queue1.isEmpty()) && (queue2.isEmpty());
}
}
@Test
public void test(){
MyStack myStack = new MyStack();
//System.out.println(myStack.empty());
myStack.push(1);
myStack.push(2);
System.out.println(myStack.top());
System.out.println(myStack.top());
System.out.println(myStack.top());
//System.out.println(myStack.empty());
}