递归
- 从结束条件开始分析
字符串
- 遇到需要记录字符的情况,可以使用
int a[26]
代替map
双指针
双指针的选择会出现在很多情况,如:快速排序算法m值的选择、列出排列组合的所有情况。
- 一般先对数组排序,然后从边界开始就能简单的定一议二
图
判断二分图
染色,然后使用bfs或dfs遍历所有节点,不应该存在相邻节点颜色一样。
复杂条件
问题允许存在变量
如判断一个字符串是否回文,而且允许删除一个字符。那么对于这个问题的变量就是如果要删除,是删除左边还是右边。但是主要的判断依旧是相同的str[i++]==str[j--]
。
所以可以分离主要的判断程序,在主程序中使用||
运算符来解决变量引起的讨论。如:return func(删左边)||func(删右边)
删除链表上第n个结点
- 快慢指针,当快指针的next是空的时候,慢指针刚好指到倒数第n个节点
前缀和
通常,涉及连续子数组问题的时候,我们使用前缀和来解决。
我们令$P[i] = A[0] + A[1] + … + A[i]$。那么每个连续子数组的和sum(i,j)就可以写成$P[j] - P[i-1](其中 0 < i < j;0 < i < j)$的形式。
任意范围连续元素的和
两个前缀和相减就能得到任意范围连续元素的和,如前5个元素的前缀和间前3个元素的前缀和就得到4~5的和。
哨兵
使用哨兵能简化我们的讨论,去掉不必要的分类讨论。如在链表中使用虚拟的头和尾,省去了分类讨论。
循环
- 遍历一个 完整 的循环会节省很多讨论,何为完整,类似与判断波的一个完整周期
单向栈
快速幂
- 计算一个数a的n次方
- 当n是偶数,我们先计算a的n/2次方,然后平方
- 当n是奇数,我们先计算a的n-1次方,然后乘n
运算模拟
使用链表模拟加减乘除时可以使用预处理以下将要运算的节点,都存在则正常进行,否则用一个无关数替代(乘法用1,加法用0等),省去额外的判断。