数据结构与算法知识点整理

数据结构与算法

基础结构

数组
链表
Trie树

基本算法

双指针
  • 快慢指针
排序算法
分治
贪心
动规
基本dp
状态压缩dp
树形dp
图论
基本数据结构
  • 邻接表
    • 适用于稀疏图
    • 适用于需要遍历边的情况
  • 邻接矩阵
    • 适用于稠密图
    • 适用于需要快速获取两点之间权值的情况
基础算法
  • BFS
  • DFS
最短路径
  • 单源无权最短路径

    • BFS
  • 单源带权最短路径

    • 对于有负环的有向图,一定无法通过传统算法找到最短路径,路径可以一直减少到负无穷(一直在环内循环)

    • 对于有负权边的无向图,也一定无法通过传统算法找到最短路径,因为无向图向有向图(转换为双向有向图)转变时会产生负环

    • Dijkstra算法

      • 原理

        • 贪心思想,采用优先队列,每次从加入点集的顶点中取出代价最小的点,将其从优先队列弹出,且标记为visit, 并用该点松弛与该顶点直接连接的顶点,如果可以被松弛且visit标志不为true,则加入优先队列中
      • 特点

        • 每一次优先队列的弹出操作都已经找到了起点到弹出点的最短路径,所以最多弹出n 次(实际上由于点可能会被重复添加,故最差应该等于边数)即可找到起点到所有点的最短路径
      • 时间复杂度

        • 顶点可能被添加到优先队列中的次数最多为边数,因为每条边最多被访问两次,故为O(ElogE),此时每次要判断当前弹出节点对应的权值是否已经被确定为最优,如果已经被确定了则跳过
        • 实际上在手动实现优先队列时能达到IO(ElogV),用unordered_map存储节点在优先队列中的索引,再通过索引更新权值,更新之后再更新unordered_map中对应的索引
      • 适用性

        • 该算法只适用没有负权的带权最短路径问题
        • 对于带有负权边的有向无环图(DAG),可以使用可重入的Dijkstra算法,即不用visit数组表示该点是否已经被确定为最优,只要可以松弛即加入优先队列,一直到队列为空,此时对于带有负环的有向图,则会无限循环,此时可以根据某个点加入队列的次数判断是否有环(一个节点进入队列n次一定有环,因为n次松弛在有向无环图中代表经过了n个节点,节点最多有n个)
      • 算法实现(基于C++ STL的priority_queue)

      1
      2
      3
      4
      5
      #include<bits/stdc++.h>
      using namespace std;
      int main(){
      return 0;
      }
    • Bellman-Ford

      • 原理
        • n个节点最多被松弛n次即可达到最短路径
      • 特点
        • 采用n次循环的方式遍历每一条边,当遍历完成即可得到源点到所有点的最短路径,因为每次松弛都可以得到最短路径上的一个节点, 而一条最短路径最多经过n个节点
        • 在有负权边的有向无环图中变现良好
    • SPFA

      • 原理
        • 优化的Bellman-Ford,只将松驰过的节点加入到队列中,因为本次如果没有松弛该节点,则该节点就是被松弛过且已经使用该节点松驰过其他节点,再次加入队列没有意义;其中对于队列中已经存在的节点只做松弛,不加入队列,因为队列中放的是点集,松弛即更新dist数组,则弹出该节点就用的是最新的权值
      • 特点
        • 在有负权边的有向无环图中变现良好
  • 多源带权最短路径

    • Floyd-Warshall
关键路径
  • 待学习
连通性
  • 并查集
最小生成树
  • Prim
  • Kruskal
AOE/AOV网
  • 拓扑排序
最大流及费用最大流
  • 待学习

进阶算法

  • 原地hash

  • AC自动机

  • 树状数组

  • KMP

  • 快速幂

  • 单调栈

  • 单调队列

  • 线段树

  • 扫描线

  • 马拉车算法(Manacher‘s Algorithm)

  • 埃氏筛法(筛素数的算法)

  • 最小表示法

    进阶知识

  • a mod m的乘法逆元是 am2,其中m为质数

  • 多重集合的排列组合是 n!(n1!n2!),其中n1是第一种元素的个数,n是总元素个数

    推荐链接

    leetcode算法笔记
    算法wiki