java栈和队列的实际应用_Java/4_栈和队列.md at master · zwqxixi/Java · GitHub

栈和队列

一、栈的典型应用

*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 时,对应的无权图。

17c166950a9778cd19d3c9ec1a6ee37e.png

- n = 5 时,对应的无权图。

918dd3bb67ca83f9d1393ba9f6b1addb.png

n = 6 时,对应的无权图。

7ade6555b44ff2663098149858c07c44.png

// 由无权图的性质,最短路径通过 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 可表示成如下无权图:

8b53574eaefd1fa4c20b5bb7dcea050c.png

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());

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值