首页 > 其他分享 >[刷题技巧] 栈和队列相关知识点汇总

[刷题技巧] 栈和队列相关知识点汇总

时间:2023-12-24 16:01:15浏览次数:36  
标签:知识点 ArrayDeque 队列 元素 数组 public 单调 刷题

栈主要考察单调栈,队列主要考察优先队列(堆)。

栈和队列(ArrayDeque)

数据结构

ArrayDeque类是双端队列Deque接口的实现类。
Deque的含义是"double ended queue",即双端队列,它既可以当作栈使用,性能优于Stack,也可以当作队列使用,性能优于LinkedList。

ArrayDeque和LinkedList是Deque的两个通用实现。

具有以下特征:

  1. ArrayDeque是采用数组方式实现的双端队列。
  2. ArrayDeque的出队入队是通过头尾指针循环,利用数组实现的。
  3. ArrayDeque容量不足时是会扩容的,每次扩容容量增加一倍。
  4. ArrayDeque可以直接作为栈使用。当用作栈时,性能优于Stack,当用于队列时,性能优于LinkedList。
  5. 非线程安全队列,无同步策略,不支持多线程安全访问。
  6. 具有fail-fast特性,不能存储null值,支持双向迭代器遍历。

类图

成员变量

transient Object[] elements;
存储元素的数组

transient int head;
队列头位置

transient int tail;
队列尾位置

private static final int MIN_INITIAL_CAPACITY = 8;
一个新创建的队列的最小容量

ArrayDeque从名字看出底层是通过数组实现,为了满足可以同时在数组两端插入或删除元素的需求,要求数组必须是循环的,即循环数组。也就是数组的任何一点都可能被看做起点或者终点。另外,该容器不允许存放null元素。底层实现是数组+双指针

构造函数

  • public ArrayDeque(Collection<? extends E> c):将现有集合元素C加入队列进行构造
  • public ArrayDeque(int numElements):创建一个指定大小的ArrayDeque
  • public ArrayDeque():无参构造方法,创建一个容量为16的ArrayDeque

方法

类型 方法 作用
添加元素 public void addFirst(E e) 在数组前面添加元素
public void addLast(E e) 在数组后面添加元素
public boolean offerFirst(E e) 在数组前面添加元素,并返回是否添加成功
public boolean offerLast 在数组后面添加元素,并返回是否添加成功
删除元素 public E pollFirst() 删除第一个元素,并返回删除元素的值,如果元素为null,将返回null
public E removeFirst() 删除第一个元素,并返回删除元素的值,如果元素为null,将抛出异常
public E pollLast() 删除最后一个元素,并返回删除元素的值,如果为null,将返回null
public E removeLast() 删除最后一个元素,并返回删除元素的值,如果为null,将抛出异常
public boolean removeFirstOccurrence(Object o) 删除第一次出现的指定元素
public boolean removeLastOccurrence(Object o) 删除最后一次出现的指定元素
获取元素 public E getFirst() 获取第一个元素,如果没有将抛出异常
public E getLast() 获取最后一个元素,如果没有将抛出异常
队列操作 public boolean add(E e) 在队列尾部添加一个元素
public boolean offer(E e) 在队列尾部添加一个元素,并返回是否成功
public E remove() 删除队列中第一个元素,并返回该元素的值,如果元素为null,将抛出异常(其实底层调用的是removeFirst())
public E poll() 删除队列中第一个元素,并返回该元素的值,如果元素为null,将返回null(其实调用的是pollFirst())
public E element() 获取第一个元素,如果没有将抛出异常
public E peek() 获取第一个元素,如果没有返回null
栈操作 public void push(E e) 栈顶添加一个元素
public E pop() 移除栈顶元素,如果栈顶没有元素将抛出异常
其他 public int size() 获取队列中元素个数
public boolean isEmpty() 判断队列是否为空
public Iterator iterator() 迭代器,从前向后迭代
public Iterator descendingIterator() 迭代器,从后向前迭代
public boolean contains(Object o) 判断队列中是否存在该元素
public Object[] toArray() 转成数组
public T[] toArray(T[] a) 转成a数组常
public void clear() 清空队列
public ArrayDeque clone() 克隆(复制)一个新的队列

单调栈O(n)

题目引入

先讲解LeetCode1475. 商品折扣后的最终价格

解法一:暴力法

遍历整个数组,再遍历每个数字的右边所有的数,找到第一个小于或等于当前元素值的元素,减掉即可。

class Solution {
    public int[] finalPrices(int[] prices) {
        // 题目最终转化为:找到右边第一个比其小的数
        for (int i = 0; i < prices.length; i ++) {
            for (int j = i + 1; j < prices.length; j ++) {
                if (prices[j] <= prices[i]) {
                    prices[i] -= prices[j];
                    break;
                }
            } 
        }
        return prices;
    }
}

很明显上述代码的时间复杂度是O(n2),空间复杂度是O(n)。

现在有一个极限数据:[1, 2, 3, 4, ....., 9999999, 0],那么这个暴力法将会超时。
我们能不能想出一种时间复杂度为O(n)级别的算法呢?

单调栈的定义

单调栈算法是一种借助"栈"实现的算法,特征为栈内元素按照某种规则(一般为数字大小)单调

  • 单调递增栈:栈中元素从栈底到栈顶是递增的;
  • 单调递减栈:栈中元素从栈底到栈顶是递减的;

单调栈是一种算法,不是数据结构。

☆单调栈的应用场景

对于数组中的某个元素,在数组中找到它左侧(或右侧)离它最近的一个比它大(或者比它小)的数字

单调栈的模板

// 枚举每一个元素
for (int i = 0; i < n; i ++) {
	// 每当一个元素即将入栈时,判断一下栈中单调性是否是存在的
	// 如果单调性被破坏,当前元素入栈之前更新答案
	while (栈不空 && 单调性不存在) {
		// 对于单调性不存在的情况,我们需要不断的弹栈
		记录此时的答案(更新答案)
		stack.pop()
	}
	// 如果单调性没被破坏,当前元素直接入栈
	// 实际存放的是下标,不是元素值
	stack.push(i);
}




解法二:单调栈

class Solution {
    public int[] finalPrices(int[] prices) {
        // 单调递增栈,栈中存放的是索引下标
        Deque<Integer> stack = new ArrayDeque<>();
        for (int i = 0; i < prices.length; i ++) {
            while (!stack.isEmpty() && prices[stack.peek()] >= prices[i]) {
                prices[stack.peek()] -= prices[i];
                stack.pop();
            }
            stack.push(i);
        }
        return prices;
    }
}

时间复杂度分析:由于每个元素都最多入栈、出栈各一次。
总时间复杂度:O(n + n) = O(2n) ≈ O(n)
开辟一个数组用于返回结果,空间复杂度:O(n)

单调栈的特点:时空复杂度O(n)

相关题目

  • LeetCode1475. 商品折扣后的最终价格 单调递增栈
  • LeetCode739. 每日温度 单调递减栈
  • LeetCode42. 接雨水 单调递减栈
  • LeetCode84. 柱状图中最大的矩形

标签:知识点,ArrayDeque,队列,元素,数组,public,单调,刷题
From: https://www.cnblogs.com/keyongkang/p/17924464.html

相关文章

  • Python爬虫知识点(bs/find_all/正则表达式)
    格式输出 BeautifulSoup库  信息提取  正则表达式     ......
  • 【力扣】-14. 最长公共前缀|刷题打卡-JS
    编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。示例1:输入:strs=["flower","flow","flight"]输出:"fl"示例2:输入:strs=["dog","racecar","car"]输出:""解释:输入不存在公共前缀。提示:1<=strs......
  • 【力扣】-35. 搜索插入位置|刷题打卡-JS
    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(logn) 的算法。示例1:输入:nums=[1,3,5,6],target=5输出:2示例 2:输入:nums=[1,3,5,6],target=2输出:1示例......
  • C++知识点总结
    第二章1.基本数据类型int有16位,即两个字节,char只占一个字节。在VisualC++6.0中,对float提供6位有效数字,对double提供15位有效数字,并且float和double的数值范围不同。对float分配4个字节,对double和longdouble分配8个字节。2.常变量关键字const。变量的值在程序运行期间不能改......
  • Maven 知识点
    目录Maven[1]1.基础知识1.1.Maven相关目录、文件1.1.1.setting.xml文件设置1.2.POM示例1.3.基础设置2.坐标和依赖2.1.坐标2.2.依赖2.2.1.依赖范围2.2.2.传递性依赖2.2.3.优化依赖3.生命周期和插件3.1.生命周期3.2.插件3.2.1.绑定生命周期阶段3.2.2.插件设置4.仓库4.1.本地仓库4......
  • 青少年CTF-qsnctf-Web-include01&include02(多种方法-知识点较多-建议收藏!)
    PHP常见伪协议php://filter是PHP中独有的一种协议,它是一种过滤器,可以作为一个中间流来过滤其他的数据流。通常使用该协议来读取或者写入部分数据,且在读取和写入之前对数据进行一些过滤,例如base64编码处理,rot13处理等。官方解释为:php://filter是一种元封装器,设计用于数据流打开时......
  • cookie的一些知识点总结
    一、cookie的种类sessionID这个ID是会话性的,只要关闭了当前浏览器,这个ID会消失,需要调用getSessoin重新获取一个新的session会话性cookie这个cookie也是会话性的即使性cookie这个cookie只要离开的该请求或者是页面,就会消失持久性cookie这个cookie只要时间没有过期,就会存储......
  • 代码随想录算法训练营第十天 | 栈与队列理论基础,232.用栈实现队列,225.用队列实现栈
    一、栈与队列理论基础学习:1.定义栈先进后出队列先进先出2.底层实现均可以通过数组或链表进行实现二、232.用栈实现队列题目链接:LeetCode232.用栈实现队列学习前:思路:无学习后:不同方法有部分功能实现是一致的,则可以进行抽象提取,实现复用性两个栈实现队列时......
  • 2023最新高级难度Rust面试题,包含答案。刷题必备!记录一下。
    好记性不如烂笔头内容来自面试宝典-高级难度Rust面试题合集问:请解释Rust中的并行计算模型和分布式计算模型。在Rust中,你可以利用语言的并发特性来实现并行计算和分布式计算。虽然这些概念是不同的,但它们可以一起使用以提高系统的性能和扩展性。并行计算并行计算是......
  • 2023最新初级难度Ruby面试题,包含答案。刷题必备!记录一下。
    好记性不如烂笔头内容来自面试宝典-初级难度Ruby面试题合集问:什么是Ruby语言?请简要介绍一下Ruby的特点和用途。Ruby是一种面向对象的、动态类型的脚本语言,由日本人松本行弘(YukihiroMatsumoto)于1993年开发。它的设计目标是简单、易读和易于编写,同时具有强大的功能和优雅......