高级数据结构
优先队列
优先队列与普通队列的区别是保证每次取出的元素是队列中优先级最高的,优先级别可自定义(数字越大优先级别越高或者数字越小优先级别越高)。
常用场景:从杂乱无章的数据中 按照一定的顺序(或者优先级)筛选数据。例如任意给定一个数组,找出前k大的数。
优先队列的本质是一个二叉堆结构,利用一个数组结构来实现完全二叉树。
特性:
- 数组里的第一个元素array[0]拥有最高的优先级
- 给定一个下标 i,那么对于元素array[i] 而言
- 父节点对应的元素下标是(i-1)/2
- 左侧子节点对应的元素下标是2*i+1
- 右侧子节点对应的元素下标是2*i+2
- 数组中每个元素的优先级都必须要高于它两侧子节点
基本操作:
- 向上筛选:时间自由度O(logk)
- 向下筛选:时间自由度O(logk)
优先队列的初始化时间自由度是O(n),即初始化一个大小为n的堆,所需的时间自由度为O(n)。
经典例题:力扣第347题(前k个高频元素)
图
图的知识点特别多,重点掌握以下知识点:
- 图的存储和表达方式:邻接矩阵,邻接链表
- 图的遍历:深度优先,广度优先
- 二部图的检测(Bipartite),树的检测,环的检测:有向图和无向图
- 拓扑排序
- 联合-查找算法(Union-Find)
- 最短路径:Dijkstra,Bellman-Ford
经典例题:力扣第785题(判断二分图)
前缀树
前缀树也称字典树,被广泛运用于字典查找中。
字典查找:例如给定一系列构成字典的字符串,要求在字典中找出所有以“ABC”开头的字符串。
应用场景:例如搜索框输入搜索文字,会罗列以搜索字为开头的相关搜索;又比如输入法的联想输出功能。
重要性质:
- 每个节点至少包含两个基本属性
- children:数组或者集合,罗列出每个分支当中包含的所有字符
- isEnd:布尔值,表示该节点是否为某字符串的结尾
- 根节点是空的
- 除了根节点,其他所有节点都可能是单词的结尾,叶子结点一定都是单词的结尾
最基本的操作:
- 创建:方法是(1)遍历一遍输入的字符串,对每个字符串的字符进行遍历;(2)从前缀树的根节点开始,将每个字符加入到节点的children字符集中;(3)如果字符集已经包含了这个字符,跳过;(4)如果当前字符是字符串的最后一个,把当前节点的isEnd标记为真。
- 搜索:方法是从前缀树的根节点出发,逐个匹配输入的前缀字符,如果遇到了继续往下一层搜索,如果没遇到则立即返回。
经典例题:力扣第212题(单词搜索II)
线段树
线段树是一种按照二叉树的形式存储数据的结构,每个节点保存的都是数组里某一段的总和。
假设有一个数组array[0,1…n-1],里面有n个元素,需要经常对这个数组做两件事,即更新数组元素的数值和求数组任意一段区间内元素的总和或者平均值。使用线段树可以将时间复杂度控制在O(logn)。
例如数组是[1,3,5,7,9,11]
根节点保存的是所有元素的和,左右子节点保存的是前一半和后一半元素的和,以此类推,叶子结点保存的就是每一个元素的值。
经典例题:力扣第315题(计算右侧小于当前元素的个数)
树状数组
树状数组(Binary Indexed Tree)是利用数组来表示多叉树的结构,有如下特征:
- 树状数组的第一个元素是空节点
- 如果节点tree[y]是tree[x]的父节点,那么需要满足y=x-(x&(-x))
假设有一个数组array[0,1…n-1],里面有n个元素,需要经常对这个数组做两件事,即更新数组元素的数值和求数组前k个元素的总和或者平均值。线段树也可以解决这个问题,但这里并不是任意一段区间所以也可以采用树状数组来解决问题,时间复杂度也为O(logn)。
经典例题:力扣第308题(二维区域和检索-可变)