leetcode刷题阶段总结(20220905)

153 阅读3分钟

算法题型与解法总结

还是要思路清晰,能够分析出问题情景,及与其匹配的算法。现阶段很多题都是看了题解思路就明白,但是自己就是想不明白。

集合 + dp

子集状压dp
  1. 通过集合状态的转变对场景进行处理(由001 -> 010)
  2. 可以考虑转换思考维度, 从横向转成竖向再进行(集合的遍历) (==LCP 53.守护太空城==)
  3. 集合转变的递推式(可以是每次+1, 也可以根据场景进行灵活改动 比如由 [1100 -> 1110, 增加了最后一个1])

集合

  1. (m-1) & j 是求(j 在m 里面的补集)
  2. a&(-b) 或 (a^b) &a , 是求a-b的差集
  3. 遍历所有子集(会有重复子集) pre=mask; while true:pre=(pre-1)&mask

  1. 判断子树相同:
    • 对子树进行序列化,类似于(a,(null),(null))
    • 给每个不同的子树进行编号, 使用三原则(node.val, idx(node.left), idx(node.right) ) 可以唯一确认一个子树
  2. 求树的直径

连通图

  1. dfs时间戳: 可以用来判断是否某结点的子孙结点(==2232题==)
  2. (无环连通图)删除边的枚举方式: 如果以某一点为root结点开始遍历,则使用遍历结点的方式遍历(此结点与其父结点的边)即可
  3. 无向图,进行遍历的时候,记录父结点,避免进行循环遍历

dp

  1. 注意点

    • 状态转移公式
    • 初始值
  2. 场景分析

    • 划分型dp(==2369题==)
    • 子序列 + 相邻 dp(==2370题==)
    • 数位dp(==2376题==)

深搜广搜

贪心

  1. 要点
    • 有序
    • 确认排序后,贪心的条件是否满足
  2. 使用场景
    • 分组贪心模拟(==2375题==)

行列式

  1. 可先对(行/列聚合)后再进行处理

前缀和

前缀和的前缀和
  1. 思路转化 (==2281题==)
    • sum(min(子序列) * sum(子序列)) = v * (所有包含V的子序列的和) = v * [sum(L,R 内所有子序列)] 【注意L和R的边界】
    • [sum(L,R 内所有子序列)] 可以使用前缀和的前缀和计算

子序列(非连续的子串)

  1. 思路:

    1. 所有子序列, 多重条件(a, b )下的和

      1. 找对一个相对固定条件,转化子序列的处理方式(比如:分别计算每个字符的贡献(==828题==) )

字符

  1. 第一思路: 使用长度为26的列表
  2. 可以使用字母枚举的情况,来提升执行

位运算

  1. 优势: 可有效缩短存储占用空间
  2. xor 的性质 a xor b xor a = b

单调栈

  1. 一般使用场景: 有比较有删除的场景

数据结构

  1. 使用堆的场景: 插入和删除操作比较多的场景,又可以保持顺序
    • 求第n大/小的场景(==2386题==)
    • 双堆模拟(==2402题==)
  2. 双向链表、双指针:无需以下标访问,更新目前指针指向比较频繁的场景
  3. 哈希表
  4. 二分搜索(适用场景很多)

组合

  1. 主要看组合的思路是否清晰,场景是否分析全面可靠,

    • 分析场景和解决方式很关键( ==参考2306题== 有i无j 和 有j无i 的组进行互换)
  2. 组合数的递推公式

    c(m,n) = c(m-1,n-1) + c(m, n-1)

  3. 使用组合的时候,注意小球是相同的,还是不同的

    • 隔板法: 在n-1个隔板中放置k个相同的小球,总情况数c(n-1, n-1+k) = c(n, n-1+k)
    • 如果有a种小球,每种小球有k个,则对原来的结果,使用乘法原理。 f(1) * * a(2) * * * * a(n)

其他

  1. 逆向思考、增量排序、记忆化搜索

  2. 求两个数的公因子

     private int gcd(int g, int num) {
            if (g == 0)
                return num;
            return  gcd(num %g, g);
        }