【面试必刷101】栈和队列

摘要

【面试必刷101】系列blog目的在于总结面试必刷101中有意思、可能在面试中会被考到的习题。总结通用性的解题方法,针对特殊的习题总结思路。既是写给自己复习使用,也希望与大家交流。

【面试必刷101】递归/回溯算法总结I(十分钟理解回溯算法)
【面试必刷101】递归/回溯算法总结II(十分钟刷爆回溯算法题)
【面试必刷101】链表
【面试必刷101】二叉树
【面试必刷101】二分查找

1 基础知识

1.1 栈和队列的性质

  • 栈:先进后出
  • 队列:先进后出

看图比较好理解:
在这里插入图片描述
在这里插入图片描述

1.2 java中Deque类做栈和队列

Deque有三种用途:

  • 普通队列(一端进另一端出):
    Queue queue = new LinkedList()或Deque deque = new LinkedList()
  • 双端队列(两端都可进出)
    Deque deque = new LinkedList()
  • 堆栈
    Deque deque = new LinkedList()
Queue方法等效Deque方法
add(e)addLast(e)
offer(e)offerLast(e)
remove()removeFirst()
poll()pollFirst()
element()getFirst()
peek()peekFirst()

queue就是从尾部添加元素,头部出来元素。

堆栈方法等效Deque方法
push(e)addFirst(e)
pop()removeFirst()
peek()peekFirst()

stack就是从头部进行处理,全部都是头部的操作。

1.3 优先队列

请添加图片描述

// 小->大排序,出来的是最小的
PriorityQueue<Integer> queue2 = new PriorityQueue<Integer>((o1, o2) -> o1 - o2);
// 大->小排序,出来的是最大的
PriorityQueue<Integer> queue1 = new PriorityQueue<Integer>((o1, o2) -> o2 - o1);
  • add() - 将指定的元素插入队列。如果队列已满,则会引发异常。

  • offer() - 将指定的元素插入队列。如果队列已满,则返回false。

  • remove() - 从队列中删除指定的元素

  • poll() - 返回并删除队列的开头

其他方法含义
size()返回优先级队列的长度。
toArray()将优先级队列转换为数组,并返回它。
contains(element)在优先级队列中搜索指定的元素。如果找到该元素,则返回true,否则返回false。

2 面试必刷习题

2.1 包含min函数的栈

在这里插入图片描述
特点就是用两个栈来进行存储。一个记录当前位置的最小值,这样做的好处是相当于记录了每个位置的最小值。

import java.util.*;
import java.util.Stack;

public class Solution {
    // 用一个min栈存储最小值
    // 用一个栈存储元素
    Deque<Integer> dq = new LinkedList<>();
    Deque<Integer> minDq = new LinkedList<>();
    
    public void push(int node) {
        if (minDq.isEmpty()) {
            minDq.addLast(node);
        } else if (minDq.peekLast() < node) {
            minDq.addLast(minDq.peekLast());
        } else {
            minDq.addLast(node);
        }
        dq.addLast(node);
    }
    
    public void pop() {
        dq.pollLast();
        minDq.pollLast();
    }
    
    public int top() {
        return dq.peekLast();
    }
    
    public int min() {
        return minDq.peekLast();
    }
}

2.2 用栈实现队列

在这里插入图片描述
特点就是两个栈来实现的,往里加,一个取数据。取数据如果是空,则从加数据栈里面取。

import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        stack1.push(node);
    }
    
    public int pop() {
        if(stack2.empty()){
            //为空:将stack1的内容倒回给stack2
            while(!stack1.empty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}

2.3 滑动窗口的最大值

经典习题:滑动窗口的单调队列。

在这里插入图片描述

import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size) {
        ArrayList<Integer> res = new ArrayList<>();
        if (num.length < 3) return res;
        // 注意这个dq存的是下标
        Deque<Integer> dq = new LinkedList<>();
        for (int i = 0; i < num.length; i++) {
            if (!dq.isEmpty() && i - dq.peekFirst() >= size) dq.pollFirst();
            while (!dq.isEmpty() && num[dq.peekLast()] < num[i]) {
                dq.pollLast();
            }
            dq.addLast(i);
            if (i >= size - 1) {
                res.add(num[dq.peekFirst()]);
            }
        }
        return res;
    }
}

2.4 单调栈

单调栈只有一种应用情况: 找出每个数左边离它最近的比它大/小的数在这里插入图片描述
维护了一个单调递增的栈,怎么理解呢?

如果n位置出现了一个比m位置更小的数(m<n),那么在k位置(k>n)是不需要去判断m位置的,因为最差情况也是n位置了。所以说是维护了一个单调递增的栈去保持这种关系,可以减少判断。

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = in.nextInt();
        }
        StringBuilder sb = new StringBuilder();
        Deque<Integer> dq = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            while (!dq.isEmpty() && dq.peekFirst() >= arr[i]) {
                dq.pollFirst();
            }
            if (dq.isEmpty()) {
                sb.append("-1 ");
            } else {
                sb.append(dq.peekFirst() + " ");
            }
            dq.addFirst(arr[i]);
        }
        System.out.println(sb.toString());
    }
}

2.5 最小的K个数

优先队列的语法和使用

在这里插入图片描述

import java.util.*;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> b - a);
        for (int i = 0; i < input.length; i++) {
            if (pq.size() < k) {
                pq.add(input[i]);
            } else {
                if (!pq.isEmpty() && pq.peek() > input[i]) {
                    pq.poll();
                    pq.add(input[i]);
                }
            }
        }
        ArrayList<Integer> res = new ArrayList<Integer>();
        while (pq.size() > 0) {
            res.add(pq.poll());
        }
        Collections.reverse(res);
        return res;
    }
}

2.6 表达式求值

这道题应该不会考,因为代码量太多了。

在这里插入图片描述

3 知识点总结

这里有两道题还有点问题:

  • 寻找第K大:快排+二分的思路没办法处理
  • 表达式求值:比较复杂咋就不写了

其他题目:

  • 包含min函数的栈:辅助栈
  • 栈实现队列:辅助栈
  • 滑动窗口的最大值:有序队列
  • 单调栈:有序栈
  • 最小的k个数:优先队列

可以看到,栈可以辅助一些数据结构,做到最小值和最大值的判别之类的。同时,单调栈和单调队列一般认为是比较难的,但是只有几道典型例题,多刷刷很好理解:

  • 单调栈:找出每个数左边离它最近的比它大/小的数
  • 单调队列:找出滑动窗口中的最大值/最小值

基本上单调栈和单调队列只有上面的习题了。

4 总结

慢慢来,孰能生巧。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值