算法题型总结
一、链表常见题
1、链表翻转
方法
递归后序遍历进行处理
图示
1 | /** |
题目
2、链表合并
方法
空头节点、双指针、优先级队列
题目
3、链表遍历
方法
空头节点、快慢指针
1 | /** |
题目
二、字符串常见题
1、字符匹配
方法
动态规划+备忘录,KMP
1 | public class KMP { |
题目
2、公共子序列
方法
动态规划,二分法
题目
3、括号问题
方法
借助栈,遍历时维护插入数和需要数
1 | /** |
题目
4、回文
方法
递推,从中间向两侧扩展
1 | /** |
题目
三、数组/字符串通用解法
1、单调函数二分查找
二分查找法
1 | // 单调递减函数上,搜索左侧值 |
题目
- 1011.D天内运送包裹能力-隐式二分查找
- 162. 寻找峰值
- 33. 搜索旋转排序数组-判断在哪个递增区间
- 4. 寻找两个正序数组的中位数 - 两个数组
- 410. 分割数组的最大值 - 难于发现隐示二分查找
- 875. 爱吃香蕉的珂珂 - 隐示二分查找
2、二维数组排序
首尾两个元素进行排序,第一个元素排序基于问题解决方案,第二个排序用于简化编程(只处理当前元素,不会处理之前扫描过的元素)
题目
- 435. 无重叠区间 - 尾升即可
- 452. 用最少数量的箭引爆气球 - 尾升即可
- 1024.视频拼接 - 首升尾降
- 1288. 删除被覆盖区间 - 首升尾降
- 56. 合并区间 - 首升尾降
- 354. 俄罗斯套娃信封问题 - 首升尾降 转为求尾单调递增子序列
- 普通解法容易超时
3、二维数组求交集
双指针+计算交集(计算交集左右边界)
1 | // 986. 区间列表的交集 |
题目
4、差分数组
转为相对落差图
1 | /** |
题目
5、前缀和
1 | /** |
6、用Map降低时间复杂度
1 | bool isPossible(vector<int>& nums) { |
题目
7、DFS/回溯/深度遍历/暴力破解
1 | // 695. 岛屿最大面积 |
题目
- 130. 被围绕的区域
- 37. 解数独
- 51. N 皇后
- 695. 岛屿的最大面积
- 698. 划分为k个相等的子集 - 需要多次合适剪枝,很容易超时
- 79. 单词搜索
- 797. 所有可能的路径
- 931. 下降路径最小和
8、数组排列
1 | // 78.子集 |
题目
9、二维数组对角线遍历
通过row+col的和判断是处于向上/向下,来计算下个坐标。
题目
10、双指针
1 | // 82. 删除排序链表中重复元素 |
题目
- 18. 四数之和
- 209. 长度最小的子数组
- 26. 删除有序数组中的重复项
- 27. 移除元素
- 283. 移动零 — 可看作删除零 + 补零
- 43. 字符串相乘
- 83. 删除排序链表中的重复元素
- 82. 删除排序链表中的重复元素 II
11、双指针+窗口
1 | public boolean checkInclusion(String s1, String s2) { |
题目
12、单调队列
题目
13、单调栈
题目
- 42. 接雨水 - 也可以直接找出最大,分两侧计算
- 496. 下一个更大元素 I - 从后往前构建单调栈
- 503. 下一个更大元素 II - 循环查找时,把数组扩为2倍
- 739. 每日温度 - 从后往前构造单调栈
14、负数代表下标存在
用元素的正负,替代Map来标识元素是否存在
题目
15、二维数组螺旋遍历
1 | /** |
题目
四、二叉树
1、层级遍历/广度遍历
方法
借助双端队列
1 | public List<List<Integer>> levelOrder(TreeNode root) { |
题目
2、先序/中序/后序遍历
题目
- 112.路径总和
- 113.路径总和 II
- 124.二叉树中的最大路径和
- 129. 求根节点到叶节点数字之和
- 1373. 二叉搜索子树的最大键值和
- 236. 二叉树的最近公共祖先
- 297. 二叉树的序列化与反序列化
- 538. 把二叉搜索树转换为累加树 - 中序遍历
- 543. 二叉树的直径 - 后序遍历
- 652. 寻找重复的子树 - 后序遍历
3、完全二叉树/利用节点位置
1 | // 662.二叉树最大宽度 |
题目
4、二叉搜索树
1 | // 96. 不同的二叉搜索树 |
题目
- 240. 搜索二维矩阵 II - 右上角为根的二叉搜索树
- 701. 二叉搜索树中的插入操作
- 95. 不同的二叉搜索树 II - 构造二叉搜索树 + 二叉树序列化 + 全排列
- 96. 不同的二叉搜索树
- 98. 验证二叉搜索树 - 先序和后序都可以
5、构造二叉树
题目
五、动态规划
方法
状态转移方程 + 状态压缩(可选)+ 正确遍历方向。
当有明显的一维/二维坐标规律移动,不是跳动的情况时,可以通过正向方式递推。否则使用自顶而下的递归更容易。如514. 自由之路不适合用正向。
1、01背包
1 | /** |
题目
2、其他
题目
- 121.买卖股票的最佳时机
- 122.买卖股票的最佳时机 II
- 123.买卖股票的最佳时机 III
- 188. 买卖股票的最佳时机 IV
- 714. 买卖股票的最佳时机含手续费
- 309. 最佳买卖股票时机含冷冻期
- 1312. 让字符串成为回文串的最少插入次数
- 152. 乘积最大子数组 - 难点转移方程
- 53. 最大子数组和
- 213. 打家劫舍 II - 环形
- 337. 打家劫舍 III - 树形
- 300. 最长递增子序列
- 312. 戳气球 - 转移方程 + 遍历方向
- 322. 零钱兑换
- 329. 矩阵中的最长递增路径
- 354. 俄罗斯套娃信封问题 - 也可转为最长递增子序列和二分法
- 514. 自由之路
- 583. 两个字符串的删除操作 - 编辑距离
- 712. 两个字符串的最小ASCII删除和 - 编辑距离
- 72. 编辑距离
- 62. 不同路径
- 651. 4键键盘 - 需要合适剪枝
- 887. 鸡蛋掉落 - 需要二分减小复杂度
六、数据结构设计
1 | // 855. 考场就坐 |
题目
- 146. LRU 缓存
- 155. 最小栈
- 170. 两数之和 III - 数据结构设计
- 225. 用队列实现栈
- 232. 用栈实现队列
- 295. 数据流的中位数
- 341. 扁平化嵌套列表迭代器 - 惰性展开
- 355. 设计推特
- 460. LFU 缓存
- 855. 考场就座
- 895. 最大频率栈
七、算法
1、DIJKSTRA
题目
2、拓扑排序
1 | class Solution { |
题目
3、分治
题目
4、并查集
计算连通性-参考
1 | class UF { |
优化版:
1 | class UF { |
题目
5、贪心
题目
八、数学
1、计算器
1 | // 772.计算器III |
题目
2、随机数
题目
- 380. O(1) 时间插入、删除和获取随机元素 - 数组 + Map + Rand函数
- 382. 链表随机节点 - 遍历链表,每个元素选中概率为1/n
- 398. 随机数索引 - 同382
- 470. 用 Rand7() 实现 Rand10() - 可通过1/2和1/5凑
- 710. 黑名单中的随机数 - 利用黑明单元素到正常元素的映射
3、字典序
力求局部递增/递减 or 多叉树计算前缀根的节点数
题目
- 31. 下一个排列—尾部降序子序列,找到大于之前的元素进行交换,然后降序序列两两交换变为升序
- 316. 去除重复字母
- 402. 移掉 K 位数字
- 440. 字典序的第K小数字 - 10叉树,难点求前缀根的节点数
4、数学规律
1 | // 870.优势洗牌-田忌赛马 https://labuladong.gitee.io/algo/2/22/64/ |
题目
- 172. 阶乘后的零
- 793. 阶乘函数后 K 个零
- 191. 位1的个数
- 204. 计数质数
- 221. 最大正方形
- 372. 超级次方 - 平方的递推方程a^123 = a^3 * (a^12)^10
- 48. 旋转图像 - 用两次翻转代替旋转
- 870. 优势洗牌 - 田忌赛马
- 969. 煎饼排序 - 选当前范围最大的翻转到底部
5、脑筋急转弯
题目
九、编程细节
1、Integer类型用equals进行判断相等
2、Interger类型用Integer.compare方法进行比较,防止直接减溢出。
3、链表操作时,可增加一个空头节点,易处理第一个节点的删除情况。