快速通关BAT算法-栈和队列

本文概要

栈和队列是大厂面试中常考的算法题,但题型较为固定,如果着急面试,则不太适合花大量时间去研究,熟悉以下四道题可以最快的速度来应对栈和队列相关面试

  1. 最小栈

  2. 两个栈组成一个队列

  3. 栈排序

  4. 栈逆序

1.最小栈

问题描述

设计一个支持 push ,pop ,getMin 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。

pop() —— 删除栈顶的元素。

getMin() —— 检索栈中的最小元素。

问题举例



解题思路

设计俩个栈:dataStack存放栈的数据,minStack存放栈的最小值。

当插入数据时,如果插入的元素比minStack最小元素大,将最小值重复入栈

当弹出数据时,dataStack栈和minStack栈中的一个元素。

代码展示

public class MinStack implements Mystack{
    private Stack<Integer> dataStack = new Stack<>();//存储数据的栈,与正常栈功能相同
    private Stack<Integer> minStack = new Stack<>();//保存最小值


    public void push(int newNum) {
        if (this.minStack.isEmpty()) {
            //最小值的栈是空的直接压入
            this.minStack.push(newNum);
        } else if (newNum <= minStack.peek()) {
            //插入元素小于等于当前栈顶元素,也压入栈中
            this.minStack.push(newNum);
        } else {
            //插入的元素比当前栈中最小值大,将最小值重复入栈
            this.minStack.push(this.minStack.peek());
        }
        //数据压入数据栈
        this.dataStack.push(newNum);
    }


    public int pop() throws Exception {
        //栈空报错
        if (this.dataStack.isEmpty()) {
            throw new Exception("栈空,无数据返回");
        }
        //同时弹出数据栈和最小值栈中的一个元素
        int pop = this.dataStack.pop();
        this.minStack.pop();
        return pop;
    }


    public int getMin() throws Exception {
        if (this.minStack.isEmpty()) {
            //最小值栈空报错
            throw new Exception("栈空");
        }
        return this.minStack.peek();
    }
}

2.两个栈组成一个队列

问题描述

用两个栈实现一个队列

问题举例


解题思路

一个栈作为压入栈,在压入数据时只往这个栈中压入,记为pushStack;
另一个栈只作为弹出栈,在弹出数据时只从这个栈弹出,记为popStack。
实现这个有俩个关键点

  • 如果popStack不为空,pushStack绝对不能向popStack中压入数据。

  • 如果popStack为空,pushStack要往popStack中压入数据。且必须一次性把pushStack中的数据全部压入。

代码展示

public class TwoStacksQueue {
    private Stack<Integer> pushStack = new Stack<>();//压入数据栈
    private Stack<Integer> popStack = new Stack<>(); //弹出数据栈
    /**
     * 入队操作
     * 直接将数据压入压入数据栈
     * @param push
     */
    public void push(int push) {
        this.pushStack.push(push);
    }
    
    /**
     * 出队操作
     * @return
     */
    public int poll() throws Exception {
        if (pushStack.isEmpty() && popStack.isEmpty()) {
            throw new Exception("队列中无数据");
        } else if (popStack.isEmpty()) {
            //弹出数据栈为空,将pushStack中的数据一次性倒入popStack            while (!pushStack.isEmpty()) {
                popStack.push(pushStack.pop());
            }
        }
        return popStack.pop();
    }


    /**
     * 返回队头元素
     * @return
     * @throws Exception
     */
    public int peek() throws Exception {
        if (pushStack.isEmpty() && popStack.isEmpty()) {
            throw new Exception("队列中没有数据");
        }else if (popStack.isEmpty()) {
            //弹出数据栈为空,将pushStack中的数据一次性倒入popStack 
            while (!pushStack.isEmpty()) {
                popStack.push(pushStack.pop());
            }
        }
        return popStack.peek();
    }
}

3.栈排序

问题描述

栈排序。编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。

问题举例


解题思路

将要排序的栈记为stack,申请的辅助栈记为help。在stack上执行pop操作,弹出的元素记为cur。

       1.如果cur小于或等于help的栈顶元素,则将cur直接压入help;

     2.如果cur大于help的栈顶元素,则将help的元素逐一弹出,逐一压入stack,直到cur小于或等于help的栈顶元素,再将cur压入help。


一直执行以上操作,直到stack中的全部元素都压入到help。最后将help中的所有元素逐一压入stack,即完成了排序。

代码展示

 public static void sortStack(Stack<Integer> stack) {
        // 辅助栈
        Stack<Integer> help = new Stack<Integer>();
        while (!stack.isEmpty()) {
            int cur = stack.pop();
            //在帮助栈不为空并且弹出的元素小于帮助栈栈顶的元素就将帮助栈栈顶的元素压会元素数据栈
            while (!help.isEmpty() && help.peek() > cur) {
                stack.push(help.pop());
            }
            //将弹出的元素放到帮助栈中
            help.push(cur);
        }
        //现在的元素全部在help栈中,且help栈从顶到栈底是 大到小的排序
        //将help中的所有元素逐一压入stack
        while (! help.isEmpty()) {
            stack.push(help.pop());
        }
    }

4.仅用递归函数和栈操作逆序一个栈

问题描述

一个栈依次压入1、2、3、4、5,那么从栈顶到栈底分别为5、4、3、2、1。将这个栈转置后,从栈顶到栈底为1、2、3、4、5,也就是实现栈中元素的逆序,但是只能用递归函数来实现,不能用其他数据结构。

问题举例

解题思路

每次删除并返回栈底的元素,返回的元素分别是:1、2、3、4、5,把返回的这五个元素,逆序插入到栈中。

代码展示

public class ReverseStack {
    /**
     * 将栈逆序
     * @param stack
     * @param <T>
     */
    public static <T> void reverse(Stack<T> stack) {
        //递归调用的返回条件
        if (stack.isEmpty()) {
            return;
        }
        //返回栈中最后一个值
        T andRemoveLastElement = getAndRemoveLastElement(stack);
        reverse(stack);
        stack.push(andRemoveLastElement);
    }
    
    /**
     * 删除并返回栈底的元素
     */
    public static <T> T getAndRemoveLastElement(Stack<T> stack) {        //讲一个值弹出栈
        T result = stack.pop();
        //栈空返回栈底元素
        if (stack.isEmpty()) {
            return result;
        } else {
            //在递归调用的过程中栈底元素始终保持在last里
            T last = getAndRemoveLastElement(stack);
            //调用返回,将非栈底元素重新压入栈中
            stack.push(result);
            return last;
        }
    }
}

5.结束

如果喜欢我的文章,欢迎关注公众号we_coding,快乐学习,快速成长~

长按订阅更多精彩▼

如有收获,点个在看,诚挚感谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值