美文网首页
栈和队列

栈和队列

作者: 甜甜起司猫_ | 来源:发表于2021-08-10 17:08 被阅读0次

栈和队列

  • stack
  • queue
  • deque

deque

  • priorityQueue

插入:O(1)
查找:O(logN)

解题技巧总结

  1. 使用栈解决最具相关性/最近相关性(重复性)问题
  2. 使用queue解决先来后到问题
  3. 用栈实现队列:用两个栈解决
  4. 用队列实现栈:用两个队列解决

有效的括号

题号20

使用栈

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for (char c : s.toCharArray()) {
            if (c == '(') {
                stack.push(')');
            } else if (c == '[') {
                stack.push(']');
            } else if (c == '{') {
                stack.push('}');
            } else if (stack.isEmpty() || stack.pop() != c) {
                return false;
            }
        }
        return stack.isEmpty();
    }
}

最小栈

题号155

使用辅助栈

解题思路

借用一个辅助栈min_stack,用于存获取stack中最小值。

算法流程

  1. push()方法: 每当push()新值进来时,如果 小于等于 min_stack栈顶值,则一起push()到min_stack,即更新了栈顶最小值;
  2. pop()方法: 判断将pop()出去的元素值是否是min_stack栈顶元素值(即最小值),如果是则将min_stack栈顶元素一起pop(),这样可以保证min_stack栈顶元素始终是stack中的最小值。
  3. getMin()方法: 返回min_stack栈顶即可。

min_stack作用分析:

  1. min_stack等价于遍历stack所有元素,把升序的数字都删除掉,留下一个从栈底到栈顶降序的栈。
  2. 相当于给stack中的降序元素做了标记,每当pop()这些降序元素,min_stack会将相应的栈顶元素pop()出去,保证其栈顶元素始终是stack中的最小元素。

复杂度分析

  1. 时间复杂度 O(1)O(1) :压栈,出栈,获取最小值的时间复杂度都为 O(1)O(1) 。
  2. 空间复杂度 O(N)O(N) :包含 NN 个元素辅助栈占用线性大小的额外空间。
class MinStack {

    private Stack<Integer> data;
    private Stack<Integer> helper;

    /** initialize your data structure here. */
    public MinStack() {
        data=new Stack<>();
        helper=new Stack<>();
    }
    
    public void push(int val) {
        data.add(val);
        if(helper.isEmpty()||helper.peek()>=val){
            helper.add(val);
        }
    }
    
    public void pop() {
        if(!data.isEmpty()){
            int top=data.pop();
            if(top==helper.peek()){
                helper.pop();
            }
        }
    }
    
    public int top() {
        return data.peek();
    }
    
    public int getMin() {
        return helper.peek();
    }
}

84 柱状图的最大面积

  • 利用栈存放尚未找到右边界的下标,当找到高度比自身小的柱形,则出栈并记录自身宽度,栈中始终保存当前尚未找到右边界,也就是最小高度的柱形下标。
  • 利用两个数组记录当前下标对应的柱状所能组成最大面积的宽度的左右下标,用于计算面积。
class Solution {
    public int largestRectangleArea(int[] heights) {
        int n=heights.length;
        int[] left=new int[n];
        int[] right=new int[n];
        Arrays.fill(right,n);

        Stack<Integer> stack=new Stack<>();
        for(int i=0;i<n;i++){
            while(!stack.isEmpty()&&heights[stack.peek()]>=heights[i]){
                right[stack.peek()]=i;
                stack.pop();
            }
            left[i]=stack.isEmpty()?-1:stack.peek();
            stack.push(i);
        }
        int area=0;
        for(int i=0;i<n;i++){
            area=Math.max(area,((right[i]-left[i]-1)*heights[i]));
        }

        return area;
    }
}

239 滑动窗口最大值

思路:

遍历数组,将 数 存放在双向队列中,并用 L,R 来标记窗口的左边界和右边界。队列中保存的并不是真的 数,而是该数值对应的数组下标位置,并且数组中的数要从大到小排序。如果当前遍历的数比队尾的值大,则需要弹出队尾值,直到队列重新满足从大到小的要求。刚开始遍历时,L 和 R 都为 0,有一个形成窗口的过程,此过程没有最大值,L 不动,R 向右移。当窗口大小形成时,L 和 R 一起向右移,每次移动时,判断队首的值的数组下标是否在 [L,R] 中,如果不在则需要弹出队首的值,当前窗口的最大值即为队首的数。

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]

初始状态:L=R=0,队列:{}
i=0,nums[0]=1。队列为空,直接加入。队列:{1}
i=1,nums[1]=3。队尾值为1,3>1,弹出队尾值,加入3。队列:{3}
i=2,nums[2]=-1。队尾值为3,-1<3,直接加入。队列:{3,-1}。此时窗口已经形成,L=0,R=2,result=[3]
i=3,nums[3]=-3。队尾值为-1,-3<-1,直接加入。队列:{3,-1,-3}。队首3对应的下标为1,L=1,R=3,有效。result=[3,3]
i=4,nums[4]=5。队尾值为-3,5>-3,依次弹出后加入。队列:{5}。此时L=2,R=4,有效。result=[3,3,5]
i=5,nums[5]=3。队尾值为5,3<5,直接加入。队列:{5,3}。此时L=3,R=5,有效。result=[3,3,5,5]
i=6,nums[6]=6。队尾值为3,6>3,依次弹出后加入。队列:{6}。此时L=4,R=6,有效。result=[3,3,5,5,6]
i=7,nums[7]=7。队尾值为6,7>6,弹出队尾值后加入。队列:{7}。此时L=5,R=7,有效。result=[3,3,5,5,6,7]

  • 单调队列也可以存值,题解中存的是下标。
  • 如果存值的话,每次只有新元素 大于 队列尾部的元素时,才去移除队列尾部的元素
  • 窗口左侧移出去的元素如果等于队列头部的元素,则removeFirst。
    举个例子: "543321" ,k=3
  • 队列存值的情况下,如果不将两个3都加入,当第一个3被移出时,会导致321的最大值变为2,因为3已经被移出了,因此存值的话,需要新的元素大于队列尾部元素再去移除队列尾部的元素。
  • 队列存下标的情况下,就可以只存一个3(存第二个),因为通过下标就能判断出移出的是第一个3还是第二个3。
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int[] res=new int[nums.length-k+1]; 
        Deque<Integer> deque=new LinkedList<>();
        for(int i=0;i<nums.length;i++){
            while(!deque.isEmpty()&&deque.peekLast()<nums[i]){
                deque.removeLast();
            }
            deque.addLast(nums[i]);
            if(i>=k&&nums[i-k]==deque.peekFirst()){
                deque.removeFirst();
            }
            if(i>=k-1){
                res[i-k+1]=deque.peekFirst();
            }
        }
        return res;
    }
}

相关文章

  • 数据结构——栈和队列

    用数组实现栈和队列 用栈实现队列 用队列实现栈 栈和队列的经典算法题最小间距栈宠物收养所 数组实现栈和队列 用数组...

  • 栈和队列

    用栈定义队列(出入栈) 用队列定义栈(数据队列和辅助队列)

  • Algorithm小白入门 -- 队列和栈

    队列和栈队列实现栈、栈实现队列单调栈单调队列运用栈去重 1. 队列实现栈、栈实现队列 队列是一种先进先出的数据结构...

  • 栈和队列

    栈和队列 本质上是稍加限制的线性表 栈和队列定义 栈顺序栈定义 链栈结点定义 队列顺序队列 链队列链队类型定义 链...

  • Python实现栈和队列以及使用list模拟栈和队列

    Python实现栈和队列 Python使用list模拟栈和队列

  • 算法-栈和队列算法总结

    栈和队列算法总结 1 模拟 1.1 使用栈实现队列 1.2 使用队列实现栈 2 栈的应用 2.1 栈操作 2.2 ...

  • 算法分析 [BFS、Greedy贪心] 2019-02-18

    队列 和 栈 232. 用栈实现队列 Implement Queue using Stacks双栈,出队列时,将i...

  • 实 验 四 栈和队列

    一、实验目的与要求:## 1、理解栈和队列抽象数据类型。 2、掌握栈和队列的存储结构和操作实现。 3、理解栈和队列...

  • 栈、队列和链表

    基本数据结构 栈和队列 栈和队列都是动态集合。栈实现的是一种后进先出策略。队列是一种先进先出策略。 栈 栈上的in...

  • 算法导论 基本数据结构

    MIT公开课没有讲到的内容,介绍几种基本数据结构- 栈和队列- 链表- 二叉树 栈和队列 栈和队列都是动态集合,元...

网友评论

      本文标题:栈和队列

      本文链接:https://www.haomeiwen.com/subject/qfhfbltx.html