刷题推荐:https://programmercarl.com/
C++ 必备知识:
- vector 用法
- unordered_set 与 unordered_map
- string 字符串操作
- sort 排序函数
- stack, queue, deque 数据结构
- priority_queue
- 二分查找
链表
主要考察哨兵结点,快慢指针。
快慢指针:
- fast 一次走两步,slow 一次走一步;
- fast 先走 k 步,slow 才开始走,两者速度相同。
如何确定链表中间位置?
快慢指针,快指针一次走两步,慢指针一次走一步,快指针走到末尾时,慢指针就在中间位置。
ListNode* fast=head, *slow=head;
while(fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
}
- 反转链表(LeetCode 206)[ 原题 | 题解 ]
- 相交链表(LeetCode 160)[ 原题 | 题解 ]
- 合并两个有序链表 (LeetCode 21)[ 原题 | 题解 ]
- 分隔链表 (LeetCode 86)[ 原题 | 题解 ]
- 环形链表 II (LeetCode 142)[ 原题 | 题解 ]
- 反转链表 II (LeetCode 92)[ 原题 | 题解 ]
- 复制带随机指针的链表(LeetCode 138)[ 原题 | 题解 ]
- 移除链表元素(LeetCode 203)[ 原题 | 题解 ]
- K 个一组翻转链表(LeetCode 25)[ 原题 | 题解 ]
- 回文链表(LeetCode 234)[ 原题 | 题解 ]
- 奇偶链表(LeetCode 328)[ 原题 | 题解 ]
- 从尾到头打印链表(剑指Offer 06)[ 原题 | 题解 ]
- 链表中倒数第 k 个节点(剑指Offer 22)[ 原题 | 题解 ]
- 排序链表(leetcode 148)(迭代归并,有点难)
- 对链表进行插入排序(leetcode 147)
- 排序的循环链表(剑指 Offer II 029)(这题要多做!)
- 删除链表的中间节点(leetcode 2095)(快慢指针)
- 链表中的下一个更大节点(leetcode 1019)(你能单次遍历解决嘛)
- 删除排序链表中的重复元素 II(leetcode 83)
- 重排链表(leetcode 143)
栈
经典题目,其中计算器的加减乘除都要会!
- 有效的括号(LeetCode 20)[ 原题 | 题解 ]
- 基本计算器(LeetCode 224)[ 原题 | 题解 ]
- 验证栈序列(LeetCode 946)[ 原题 | 题解 ]
单调栈,这种题目往往需要存储下标,而不是元素本身。
- 最小栈(LeetCode 155)[ 原题 | 题解 ]
- 每日温度(LeetCode 739)[ 原题 | 题解 ]
- 移掉 K 位数字(LeetCode 402)[ 原题 | 题解 ]
- 接雨水(leetcode 42)
- 柱状图中最大的矩形(leetcode 84)
队列
- 用栈实现队列(LeetCode 232)[ 原题 | 题解 ]
考察队列满空条件
- 设计循环双端队列(LeetCode 641)[ 原题 | 题解 ]
单调队列(难)
- 滑动窗口最大值(LeetCode 239)[ 原题 | 题解 ]
排序
快排不稳定,发生在什么时候?
中枢元素和 nums[++p] 进行交换的时候会导致不稳定,如 2 2 1,基准元素是 1,无论怎样做,两个 2 的位置都会反过来。
合并排序,两个有序数组合并非常重要
- 合并两个有序数组(leetcode 88)[ 原题 | 题解 ]
- 合并 K 个升序链表(LeetCode 23)[ 原题 | 题解 ]
- 有序数组的平方(LeetCode 977)[ 原题 | 题解 ]
逆序对(难),建议树状数组,归并排序也要会!
- 数组中的逆序对(剑指 Offer 51)[ 原题 | 题解 ]
- 计算右侧小于当前元素的个数(leetcode 315)[ 原题 | 题解 ]
- 翻转对(leetcode 493)
- 区间和的个数(leetcode 327)(使用前缀和转化为逆序对)
快排
- 数组中的第K个最大元素(leetcode 215)
计数排序
todo
奇怪的排序(难)
- 颜色分类(LeetCode 75)[ 原题 | 题解 ]
- 面试题 16.16] 部分排序 [ 原题 | 题解 ]
下面两题和排序无关
- 盛最多水的容器(LeetCode 11)[ 原题 | 题解 ]
- 两数之和(LeetCode 1)[ 原题 | 题解 ]
- 数组中的 k-diff 数对(leetcode 530)
贪心
贪心,可能会用到排序
- 分发饼干(LeetCode 455)
- 柠檬水找零(leetcode 860)
- 跳跃游戏(LeetCode 55)
- 摆动序列(LeetCode 376)
- 买卖股票的最佳时机 II(LeetCode 122)
- 加油站(LeetCode 134)
- 移掉 K 位数字(LeetCode 402)
贪心区间,需要排序
- 用最少数量的箭引爆气球(leetcode 452)
- 合并区间(LeetCode 56)
三数问题,注意去重的技巧!
- 三数之和(LeetCode 15)
- 最接近三数之和(LeetCode 16)
- 有效三角形的个数(leetcode 611)
二分查找
二分查找适合在有序数组内进行查找,时间复杂度为 l o g ( n ) log(n) log(n)
- 二分查找(leetcode 704)[ 原题 | 题解 ]
- 搜索插入位置(leetcode 35)[ 原题 | 题解 ]
- 搜索二维矩阵(leetcode 74)
- 第一个错误的版本(leetcode 278)
- 有效的完全平方数(leetcode 367)
二分查找不一定非要找到某个数,可以是比 target 小的数,也可以是比 target 大的数;有时即使等于 target,也不一定返回结果
- 在排序数组中查找元素的第一个和最后一个位置(leetcode 34)
- 在排序数组中查找数字 I(剑指 Offer 53 – I)
- 0~n-1中缺失的数字(剑指 Offer 53 - II)
二分查找不一定要求数组有序
- 搜索旋转排序数组(leetcode 33)
- 寻找峰值(leetcode 162)
- 山脉数组的峰顶索引(leetcode 852)
二维矩阵中进行二分查找
- 有序矩阵中第 K 小的元素(leetcode 378)
- 乘法表中第k小的数(leetcode 668)
二分查找进阶
- 有效三角形的个数(leetcode 611)
- 寻找两个正序数组的中位数(leetcode 4)
位运算
位 1 的个数,常见解法(x > 0):
- 每次 x &= (x-1) 直到 x == 0,记录循环次数
- 32位,每次右移一位,x >> i
2 的幂,常见解法(x > 0):
- x & (x-1),x 为 2 的幂时,结果为 0
- x & -x,树状数组中的 lowbit,x 为 2 的幂时,结果为 x
前面两种的时间复杂度其实是一样的,对于 int 都是 32.
- 位 1 的个数(LeetCode 191)
- 2 的幂(LeetCode 231)
能用动态规划来优化,我是想不到的~
异或的解法实在是想不到啊~
- 丢失的数字(LeetCode 268)
- 0~n-1中缺失的数字(剑指 Offer 53 - II)
递归
回溯
这里有回溯的题目列表:https://leetcode.cn/problems/n-queens/solutions/735755/dai-ma-sui-xiang-lu-51-n-queenshui-su-fa-2k32/
经典的 dfs
- 岛屿数量( LeetCode 200 )[ 原题 | 题解 ]
找到所有可能的组合,下面这些题目解法差不多,以 N皇后 为典型
- N 皇后(LeetCode 51)[ 原题 | 题解 ]
- 子集(LeetCode 78)[ 原题 | 题解 ]
- 括号生成(LeetCode 22)[ 原题 | 题解 ]
- 组合(LeetCode 77)[ 原题 | 题解 ]
- 组合总和 III( LeetCode 216 )[ 原题 | 题解 ]
结果去重,一定要先排序,然后比较 i 和 i-1即可
- 子集 II(LeetCode 90)[ 原题 | 题解 ]
- 组合总和 II(LeetCode 40)[ 原题 | 题解 ]
- 6352. 美丽子集的数目(这题是回溯,不能用子集的方式做)
分割回文串,和上面的情况差不多,但是有点难理解
- 分割回文串( LeetCode 131 )[ 原题 | 题解 ]
- 复原 IP 地址(leetcode 93)[ 原题 | 题解 ]
全排列问题,第二个全排列去重,这和之前的有点点不一样
- 全排列( LeetCode 46 )[ 原题 | 题解 ]
- 全排列 II( LeetCode 46 )[ 原题 | 题解 ]
回溯的时候,确定位置的指针 cur 可能是数组!
- 电话号码的字母组合(leetcode 17)[ 原题 | 题解 ]
下面这个和 N皇后 很相似,但是找到答案后如何停止回溯,一路返回?用一个标志位就行
- 解数独(leetcode 37)[ 原题 | 题解 ]
难题,回溯+剪枝 || 状态压缩+动态规划
- 火柴拼正方形( LeetCode 473 )[ 原题 | 题解 ]
- 划分为k个相等的子集(leetcode 698)[ 原题 | 题解 ]
- 公平分发饼干(leetcode 2035)
- 完成所有工作的最短时间(leetcode 1723)
回溯+大数加法
二叉树
- 二叉树的前序遍历( LeetCode 144 )
- 二叉树的中序遍历( LeetCode 94 )
- 二叉树的后序遍历( LeetCode 145 )
- 二叉树的层序遍历( LeetCode 102 )
- 二叉树的锯齿形层序遍历( LeetCode 103 )
- 二叉树的右视图( LeetCode 199 )
- 二叉树展开为链表( LeetCode 114 )
- 左叶子之和( LeetCode 404 )
- 找树左下角的值( LeetCode 513 )[ 原题 | 题解 ]
- 翻转二叉树(leetcode 226)
- 对称二叉树(leetcode 101)[ 原题 | 题解 ]
- 合并二叉树(leetcode 617)
- 平衡二叉树( LeetCode 110 )
构建二叉树
- 从前序与中序遍历序列构造二叉树( LeetCode 105 )
- 从中序与后序遍历序列构造二叉树( LeetCode 106 )
- 从前序与后序遍历序列构造二叉树
- 二叉树的序列化与反序列化( LeetCode 297 )
- 最大二叉树( LeetCode 654 )
路径,回溯
- 路径总和( LeetCode 112 )
- 路径总和 II( LeetCode 113 )[ 原题 | 题解 ]
- 路径总和 III(leetcode 437)
- 二叉树的最近公共祖先( LeetCode 236 )
难题
- 完全二叉树的节点个数( LeetCode 222 )(难)
二叉搜索树,几乎所有二叉排序树的题目都可以用中序遍历解决!
- 将有序数组转换为二叉搜索树( LeetCode 108 )
- 二叉搜索树中的搜索(leetcode 700)
- 验证二叉搜索树(leetcode 98)[ 原题 | 题解 ]
- 二叉搜索树中的众数(leetcode 501)(不要在交界处判断,因为最后一个数没有交界处)
- 把二叉搜索树转换为累加树( LeetCode 538 )
- 二叉搜索树中的插入操作(leetcode 701)
- 删除二叉搜索树中的节点( LeetCode 450 )(删除结点,如果不使用递归,需要额外记录父节点,使父节点的左孩子或者右孩子置空,比较麻烦,建议使用递归!)[ 原题 | 题解 ]
- 二叉搜索树的最小绝对差( LeetCode 530 )
- 二叉搜索树的后序遍历序列(剑指 Offer 33)
二叉搜索树,面对 low 和 high 如何处理?
- 二叉搜索树的最近公共祖先( LeetCode 235 )
- 修剪二叉搜索树( LeetCode 669 )[ 原题 | 题解 ]
动态规划
01背包,即物品有限。
- P1048 [NOIP2005 普及组] 采药 [ 原题 | 题解 ]
- P1049 [NOIP2001 普及组] 装箱问题 [ 原题 | 题解 ]
- P1164 小A点菜 [ 原题 | 题解 ]
- P1208 [USACO1.3]混合牛奶 Mixing Milk [ 原题 | 题解 ]
- P1507 NASA的食物计划 [ 原题 | 题解 ]
- P1510 精卫填海 [ 原题 | 题解 ]
二维dp怎么写,dp[i][j] 的意义是什么,for循环第一层是容量还是物品?为什么?一维dp怎么写,for循环第一层是容量还是物品?为什么?
完全背包,即物品无限。
分组背包
for 组号
for 容量
for 组内物品
- P1757 通天之分组背包 [ 原题 | 题解 ]
多重背包,是分组背包的一种特殊情况
for 物品种类
for 容量
for 该类物品数量
如果超时,则需要二进制优化为 01 背包
- P2066 机器分配 [ 原题 | 题解 ]
- P1776 宝物筛选 [ 原题 | 题解 ]
混合背包
有的物品有无穷个(完全),有的物品是有限的(多重)。先处理完全背包,再把多重背包进行二进制优化转为 01 背包。
满足某个条件的背包
- P1509 找啊找啊找GF [ 原题 | 题解 ]
二维 true false 背包
- P1877 [HAOI2012] 音量调节 [ 原题 | 题解 ]
投资股票,多次 dp
- P1853 投资的最大效益 [ 原题 | 题解 ]
简单动态规划
注意,爬楼梯(LeetCode 70) 要求序列有序,然而有一些题目不需要有序,如经典的凑硬币:面试题 08.11. 硬币。要注意这两种情况的区别!前者先循环容量再循环物品,后者先循环物品再循环容量。
- 爬楼梯( LeetCode 70 )
- 斐波那契数( LeetCode 509 )
- 使用最小花费爬楼梯(leetcode 746)
- 最大子序和( LeetCode 53 )
- 三角形最小路径和( LeetCode 120 )
- 整数拆分( LeetCode 343 )
- 不同的二叉搜索树( LeetCode 96 )(难)
迷宫题目
- 不同路径( LeetCode 62 )
- 不同路径II( LeetCode 63 )
- 地下城游戏( LeetCode 174 )(难)
股票问题,分状态进行动态规划,比较难。
- 买卖股票的最佳时机( LeetCode 121 )
- 买卖股票的最佳时机II( LeetCode 122 )
- 买卖股票的最佳时机III( LeetCode 123 )
- 买卖股票的最佳时机IV( LeetCode 188 )
- 最佳买卖股票时机含冷冻期(LeetCode 309)
- 买卖股票的最佳时机含手续费(LeetCode 714)
动态规划,相邻不能选(选中 i,那么 i-1 和 i+1 不能选)。
如果这题升级一下(美团23/3/25笔试),选中 i 后,i-2,i-1,i+1,i+2 不能选,怎么做呢?
测试样例:[3, 1, 100, 10, 11, 4]
动态规划和环结合,比较难。(其实不难,把环拆成两个序列就好了)
动态规划和二叉树结合,比较难(树形dp)。
序列问题,动态规划的经典应用,高频面试题!
- 判断子序列(leetcode 392)
- 最长递增子序列( LeetCode 300 )
- 最长连续递增序列( LeetCode 674 )
- 最长递增子序列的个数(leetcode 673)
- 最长重复子数组( LeetCode 718 )
- 最长重复子串(leetcode 1062)(数据量是 1 0 3 10^3 103使用动态规划,字符串可以重叠)
- 最长重复子串(leetcode 1044)(数据量是 1 0 4 10^4 104使用二分+字符串哈希 unsigned long,13131,字符串可以重叠)
- 最长公共子序列( LeetCode 1143 )
- 不相交的线(leetcode 1035)
- 不同的子序列(leetcode 115)
- 两个字符串的删除操作(leetcode 583)
- 编辑距离(leetcode 72)
- 最长回文子序列( LeetCode 516 )
- 最长回文子串( LeetCode 5 )
回溯 || 动态规划
- 分割等和子集( LeetCode 416 )
- P2392 kkksc03考前临时抱佛脚 [ 原题 | 题解 ]
- 目标和( LeetCode 494 )
- 最后一块石头的重量 II( LeetCode 1049 )
- 给表达式添加运算符( LeetCode 282 )
- 单词拆分 II(leetcode 140)
三指针,动态规划
- 丑数(leetcode 263)
- 丑数 II(leetcode 264)
- 计数质数(leetcode 204)
子数组问题
下图来自 https://leetcode.cn/problems/maximum-subarray/solutions/1473193/by-lfool-m8ss/
前缀和。前缀和相减即为连续区间和。
- 和为 K 的子数组(leetcode 560)
- 和等于 k 的最长子数组长度(leetcode 325)
- 除自身以外数组的乘积(leetcode 238)
- 路径总和 III(leetcode 437)
- 旋转函数(leetcode 396)
动态规划
- 最大子数组和(leetcode 53)
- 乘积最大子数组(leetcode 152)
滑动窗口
- 长度最小的子数组(leetcode 209)
- 最长不含重复字符的子字符串(剑指 Offer 48)
多路归并
可能会用到堆
- 丑数 II
- 超级丑数
- 查找和最小的K对数字
- 最小区间
- 找出第 k 小的距离对
- 有序矩阵中第K小的元素
- 第 K 个最小的素数分数
- 有序矩阵中的第 k 个最小数组和
- 子数组和排序后的区间和
- 数组的最小偏移量
循环数组
排列
- 下一个排列(leetcode 31)
- 下一个更大元素 III(leetcode 556)
- 排列序列(leetcode 60)
- 全排列(leetcode 46)
建议二刷
- 字符串的排列(剑指 Offer 38)(看看如何去重,排序去重,还是前向搜索去重)
- 二叉树的镜像(剑指 Offer 27)[ 原题 | 题解 ]
- 树的子结构(剑指 Offer 26)[ 原题 | 题解 ]
- 矩阵中的路径(剑指 Offer 12)[ 原题 | 题解 ]
奇怪的动态规划
组合数计算如 C m n C_m^n Cmn ,这种题目一般要求取模,如果通过暴力计算往往会超过最大范围(乘法不好取模),所以要用递推来写(加法可以取模)
- P1358 扑克牌 [ 原题 | 题解 ]
- P1679 神奇的四次方数 [ 原题 | 题解 ]
图
并查集只能解决无向图中的环
- 冗余连接(leetcode 684)[ 原题 | 题解 ]
有向图中的环可以使用拓扑排序或者dfs。
dfs要注意需要使用3种状态来表示节点是否被访问,还是正在被访问,还是未访问。否则会超时。
- 课程表(leetcode 207)[ 原题 | 题解 ]
- 课程表 II(leetcode 210)[ 原题 | 题解 ]
数之和
- 两数之和(leetcode 1)
- 两数之和 II - 输入有序数组(leetcode 167)
- 170. 两数之和 III - 数据结构设计
- 1099. 小于 K 的两数之和
- 259. 较小的三数之和
- 三数之和(leetcode 15)
- 16. 最接近的三数之和
- 四数之和(leetcode 18)
- 四数相加 II(leetcode 425)[ 原题 | 题解 ]
区间统计,差分数组
海量数据处理
位图法(bitmap):使用 bit 来存放数据的状态。用途:海量数据排序,海量数据去重。
Q: 对 1000,000,000 中的 900,000,000 个不重复的正整数排序?
A: 9 e 8 9e8 9e8 个 int 型数据,每个 int 是 4 个字节,因此占用 3.6 e 9 3.6e9 3.6e9 个字节,即大约 3.6 G b 3.6Gb 3.6Gb(这个大小其实现代笔记本内存没啥问题),内存难以放下。使用位图法,只需要 1 e 9 1e9 1e9 (数据的最大范围)个比特,即 1.25 e 8 1.25e8 1.25e8 个字节,大约是 125 M b 125Mb 125Mb。做法是:在内存中申请 125Mb 的空间,从外存(文件)中读取数据,将对应 bit 置 1。遍历位图,如果 bit 为 1,将该 bit 对应的数(即该 bit 的索引)写入外存文件中。使用位图法进行排序的前提是数据不重复。
Q:在2.5亿个整数中找出不重复的整数?
A: 2.5 e 9 2.5e9 2.5e9 个 int 占 1 e 10 1e10 1e10 个字节,大概就是 10Gb。对于每个数据,使用两个 bit 表示其状态。00 表示没有出现过,01 表示出现 1 次,01 表示出现多次,11 没有意义。假设最大范围是 2 32 2^{32} 232,不超过 5 e 9 5e9 5e9,每个数据需要两个比特,因此一共需要 10 e 9 10e9 10e9 个比特,大概 1.25Gb。申请 1.25Gb 的内存,从外存(文件)中读取数据,将对应 bit 置相应状态。遍历位图,如果 bit 为 01,将该 bit 对应的数(即该 bit 的索引)写入外存文件中。