第一讲 基础算法
(1) 排序
快速排序
归并排序
- LeetCode 56. 合并区间 >> 区间排序
(2) 前缀和与差分
- LeetCode.1248 统计优美子序列
- LeetCode 1191. K 次串联后最大子数组之和
- LeetCode 1170. 比较字符串最小字母出现频次
- LeetCode 1171. 从链表中删去总和值为零的连续节点 >> 前缀和+链表操作
- LeetCode 1177. 构建回文串检测
- LeetCode 1184. 公交站间的距离
- LeetCode 560. 和为K的子数组
- LeetCode 238. 除自身以外数组的乘积 >> 前缀积
- LeetCode 437. 路径总和 III >> 前缀和 + 哈希表 问题中出现某个前缀和出现多少次时,要想到使用哈希表转换为Si - T = Sj,求Sj的个数
(3) 二分
- LeetCode 35. 搜索插入位置
- LeetCode 74. 搜索二维矩阵
- LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置
- LeetCode 33. 搜索旋转排序数组
- LeetCode 153. 寻找旋转排序数组中的最小值 >> 同上
/* 版本1
当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。
如果我们的目标是下面这个v,那麽就必须使用模板 1
................vooooooooo
*/
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
/*
当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。
假设经由 check 划分后,整个区间的属性与目标v如下,则我们必须使用模板 2
oooooooov...................
所以下次可以观察 check 属性再与模板1 or 2 互相搭配就不会写错啦
*/
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
(4) 枚举与模拟
数组模拟与遍历
- LeetCode.1252 奇数值单元格的数目
- LeetCode.1253. 重构 2 行二进制矩阵
- LeetCode.1260. 二维网格迁移
- LeetCode 1207. 独一无二的出现次数
- LeetCode 54. 螺旋矩阵 >> 定义方向遍历
- LeetCode 48. 旋转图像
- LeetCode 240. 搜索二维矩阵 II >> 有序数组遍历 从右上角开始
字符串模拟
字符计数相关
- LeetCode 1221. 分割平衡字符串
- LeetCode 1234. 替换子串得到平衡字符串
- LeetCode 1247. 交换字符使得字符串相同
- LeetCode 1143. 最长公共子序列
- LeetCode 72. 编辑距离
字符前缀相关
- LeetCode 1233. 删除子文件夹
字符 栈运用
- LeetCode 1209. 删除字符串中的所有相邻重复项 II
- LeetCode 1190. 反转每对括号间的子串
双指针
- LeetCode 1156. 单字符重复子串的最大长度
- LeetCode 1169. 查询无效交易
- LeetCode 283. 移动零
- LeetCode 11. 盛最多水的容器 >> 有意思的双指针,贪心,移动短边
- LeetCode 15. 三数之和
- LeetCode 438. 找到字符串中所有字母异位词 >> 滑动窗口
- LeetCode 76. 最小覆盖子串 >> 注意左指针收缩的条件要满满足j - i 是一个正常的区间
- LeetCode 141. 环形链表 >> 判断环 快慢指针
- LeetCode 142. 环形链表 II >> 同上
// 滑动窗口
int left = 0, right = 0;
while (right < s.size()) {
// 增大窗口
window.add(s[right]);
right++;
while (window needs shrink) {
// 缩小窗口
window.remove(s[left]);
left++;
}
}
枚举 (位运算,状态压缩等)
- LeetCode.1255 得分最高的单词集合
- LeetCode 1239. 串联字符串的最大长度
- LeetCode 1238. 循环码排列
- LeetCode 1240. 铺瓷砖
- LeetCode 1178. 猜字谜
方向枚举
- LeetCode 1222. 可以打击国王的皇后
分类讨论
- LeetCode 1224. 最大相等频率
第二 数据结构
(1) 并查集
- LeetCode 1202. 交换字符串中的元素
(2) 哈希表
- LeetCode 1160. 拼写单词
- LeetCode 1163. 按字典序排在最后的子串 // 哈希字符串
- LeetCode 1189. “气球” 的最大数量
- LeetCode 49. 字母异位词分组
- LeetCode 41. 缺失的第一个正数 >> 原地哈希:将数组本身当作哈希表
- LeetCode 73. 矩阵置零
(3) 栈
- LeetCode 20. 有效的括号
- LeetCode 155. 最小栈
- LeetCode 739. 每日温度 >> 单调栈
- LeetCode 84. 柱状图中最大的矩形
- LeetCode 32. 最长有效括号 ---- 括号相关
(4) 队列
- LeetCode 1172. 餐盘栈 >> 堆(优先队列)
- LeetCode 239. 滑动窗口最大值 >> 单调栈 双端队列
- LeetCode 23. 合并K个排序链表 >> 优先队列 priority_queue<int, vector, greater>小顶堆, priority_queue<int, vector> 大顶堆
- LeetCode 347. 前 K 个高频元素 >> 优先队列
- LeetCode 295. 数据流的中位数 >> 优先队列
(5) 链表
- LeetCode 83. 删除排序链表中的重复元素
- LeetCode 160. 相交链表
- LeetCode 206. 反转链表
- LeetCode 234. 回文链表
- LeetCode 21. 合并两个有序链表
- LeetCode 2. 两数相加 >> 两数相加,从个位开始,注意进位,有意思
- LeetCode 24. 两两交换链表中的节点 >> 将前面节点后面节点存下来
- LeetCode 25. K 个一组翻转链表 >> 分组翻转,翻转:前面的去链接最后面的,然后更新最后面的节点
- LeetCode 138. 复制带随机指针的链表 >> 深度复制
- LeetCode 146. LRU缓存机制 >> 双向链表
- LeetCode 114. 二叉树展开为链表
(5) 自定义结构
- LeetCode 155. 最小栈
第三讲 搜索与图论
(1) 搜索遍历
双指针
- LeetCode 1237. 找出给定方程的正整数解
- LeetCode 105. 从前序与中序遍历序列构造二叉树
- LeetCode 287. 寻找重复数 --- 快慢指针
- LeetCode 27. 移除元素
- LeetCode 26. 删除排序数组中的重复项
- LeetCode 88. 合并两个有序数组
(2) BFS
Flood Fill
- LeetCode.1254. 统计封闭岛屿的数目
- LeetCode 102. 二叉树的层序遍历
- LeetCode 199. 二叉树的右视图
- LeetCode 200. 岛屿数量
迷宫问题
- LeetCode 1210. 穿过迷宫的最少移动次数
多元bfs
- LeetCode 1162. 地图分析
- LeetCode 994. 腐烂的橘子
(3) DFS
// 树中序遍历 迭代算法
vector<int> inorderTraversal(TreeNode* root) {
// dfs(root);
stack<TreeNode*> stk;
while (root || stk.size()) {
while (root) {
stk.push(root);
root = root->left;
}
if (stk.size()) {
root = stk.top();
stk.pop();
s.push_back(root->val);
root = root->right;
}
}
return s;
}
// 前序 迭代
class Solution {
public:
void flatten(TreeNode* root) {
auto v = vector<TreeNode*>();
auto stk = stack<TreeNode*>();
TreeNode *node = root;
while (node != nullptr || !stk.empty()) {
while (node != nullptr) {
v.push_back(node);
stk.push(node);
node = node->left;
}
node = stk.top(); stk.pop();
node = node->right;
}
int size = v.size();
for (int i = 1; i < size; i++) {
auto prev = v.at(i - 1), curr = v.at(i);
prev->left = nullptr;
prev->right = curr;
}
}
};
- LeetCode 94. 二叉树的中序遍历 >> 树遍历迭代算法
- LeetCode 104. 二叉树的最大深度
- LeetCode 101. 对称二叉树
- LeetCode 543. 二叉树的直径
- LeetCode 98. 验证二叉搜索树
- LeetCode 230. 二叉搜索树中第K小的元素
回溯
- LeetCode 46. 全排列
- LeetCode 78. 子集
- LeetCode 17. 电话号码的字母组合
- LeetCode 39. 组合总和
- LeetCode 22. 括号生成
- LeetCode 79. 单词搜索
- LeetCode 51. N 皇后
- LeetCode 131. 分割回文串
最大最小路径问题
- LeetCode 1219. 黄金矿工
- LeetCode 1261. 在受污染的二叉树中查找元素
遍历
- LeetCode 1161. 最大层内元素和
(4) 图论
- LeetCode 207. 课程表
- LeetCode 208. 实现 Trie (前缀树)
(5) 分治
- LeetCode 108. 将有序数组转换为二叉搜索树
- LeetCode 236. 二叉树的最近公共祖先
- LeetCode 124. 二叉树中的最大路径和 >> 注意dfs的返回值为节点值、节点值加上左右指数的最大值。该返回值是提供给父节点使用,因此不能返回该值加上左和右。
- LeetCode 215. 数组中的第K个最大元素 >> 快速排序
// 快速排序算法模板 —— 模板题
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
// 归并排序算法模板
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
else tmp[k ++ ] = q[j ++ ];
while (i <= mid) tmp[k ++ ] = q[i ++ ];
while (j <= r) tmp[k ++ ] = q[j ++ ];
for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}
第四讲 数学知识
(1) 约数
- LeetCode.1250
(2) 质数
- LeetCode 1175. 质数排列
(3) 欧拉函数
(4) 线性代数
- LeetCode 1232. 缀点成线
(5) 概率论
- LeetCode 1227. 飞机座位分配概率
(6) 扩展欧几里得算法
(7) 高斯消元
(8) 快速幂
(9)求组合数
(10) 容斥原理
(11) 博弈论
第五讲 动态规划
(1) 线性DP
- AcWing.898 数字三角形 -> LeetCode.1269 停在原地的方案数
- LeetCode.1278 分割回文串Ⅲ
- LeetCode.221 最大正方形+-*/ -> LeetCode.1277. 统计全为 1 的正方形子矩阵
- LeetCode 1218. 最长定差子序列
- LeetCode 1220. 统计元音字母序列的数目 -> LeetCode 1223. 掷骰子模拟
- LeetCode 1235. 规划兼职工作
- Acwing 走方格
- LeetCode 1186. 删除一次得到子数组最大和 >> 最大子区间和
- LeetCode 1187. 使数组严格递增 >> 最大上升子序列衍生
- LeetCode 42. 接雨水
- LeetCode 53. 最大子序和 >>
- LeetCode 70. 爬楼梯
- LeetCode 118. 杨辉三角 >> 二维线性规划
- LeetCode 198. 打家劫舍
- LeetCode 300. 最长上升子序列 >> 维护一个数组,这个数组存储这长度为k的序列最小结尾元素
- LeetCode 139. 单词拆分
- LeetCode 64. 最小路径和 >> 二维动态规划
- LeetCode 62. 不同路径 >> 二维动态规划
- LeetCode 5. 最长回文子串 --- 字符串相关
- LeetCode 1143. 最长公共子序列 --- 字符串相关
- LeetCode 72. 编辑距离 --- 字符串相关
(2) 背包问题
/*
1. 01背包
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i])
2. 完全背包
f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i])
*/
分组背包
- LeetCode 1155. 掷骰子的N种方法
- LeetCode 279. 完全平方数 >> 完全背包问题
- LeetCode 322. 零钱兑换 >> 装满与不装满的初始化区别 装满为f初始化大值,不装满为0
- LeetCode 416. 分割等和子集 >> 01背包
(3) 区间DP
- LeetCode 152. 乘积最大子数组
(4) 计数DP
(5) 状态压缩DP
(6) 数位DP
(7) 树形DP
(8) 记忆化DP
第六讲 贪心
(1) 数组相关
- LeetCode 1262. 可被三整除的最大和
- LeetCode 1217. 玩筹码
- LeetCode 121. 买卖的最佳时机
- LeetCode 55. 跳跃游戏 >> 更新最远点
- LeetCode 45. 跳跃游戏 II >> f(i)表示到达i坐标的最短步数,递增
(2) 区间问题
- LeetCode 763. 划分字母区间 >> 计算每个字符最后位置,扫描中不断更新位置,直到i = end为不可分割的一段;
(3) Huffman数
(4) 排序不等式
(5)绝对值不等式
(6) 推公式
第七讲 杂项
(1) 日期相关
- LeetCode 1154. 一年中的第几天
- LeetCode 1185. 一周中的第几天
(2) 数组相关
- LeetCode 189. 旋转数组
- LeetCode 169. 多数元素 >> 数组中袁术数量大于n/2的元素,为排序后的数组下边为n/2的元素
- LeetCode 31. 下一个排列 --- 字典序相关
(3) 运算相关
- LeetCode 136. 只出现一次的数字 >> 异或