1.数组与字符串
1. 双指针法
1.思路
- 通过两个指针在数组或字符串上按照特定规则移动,解决诸如查找、匹配、计算等问题。指针的移动方向和条件取决于具体问题,可相向、同向移动等。
2.经典案例
LeetCode 11. 盛最多水的容器
- 在表示竖线高度的数组上,双指针分别指向数组两端,根据指针所指高度调整指针位置,计算并更新容器最大水量。
LeetCode 167. 两数之和 II - 输入有序数组
- 在有序数组中,利用双指针从两端开始移动,根据两指针所指元素和与目标值的关系,找到和为目标值的两个数。
2.滑动窗口法
1.思路
- 在字符串或数组上维护一个窗口,通过移动窗口的起始和结束位置,动态调整窗口内元素,以满足特定条件,如寻找特定子串、子数组等。窗口大小可固定或动态变化。
2.经典案例
LeetCode 3. 无重复字符的最长子串
- 在字符串上通过滑动窗口,确保窗口内无重复字符,从而找到最长无重复子串。
LeetCode 76. 最小覆盖子串
- 在字符串 s 上利用滑动窗口,先扩大窗口使其包含字符串 t 的所有字符,再缩小窗口找到覆盖 t 的最小子串。
3.前缀和法
1.思路
- 对数组进行预处理,生成一个前缀和数组,其中每个元素表示原数组从起始位置到该位置的元素之和。利用前缀和数组可以高效解决子数组求和、特定和的子数组计数等问题。
2.经典案例
LeetCode 303. 区域和检索 - 数组不可变
- 通过前缀和数组快速计算给定区间内的元素之和。
LeetCode 560. 和为 K 的子数组
- 借助前缀和数组,统计和为 K 的子数组的个数。
2.链表
1.双指针法(链表场景)
1.思路
- 在链表上使用两个指针,根据问题需求同步或异步移动指针,用于检测链表特性(如环)、查找特定节点等。
2.经典案例
- 在判断链表是否有环的问题中(类似 LeetCode 141. 环形链表),快慢指针同时移动,快指针每次移动两步,若快慢指针相遇则存在环。
3.树
1.深度优先搜索(DFS) - 递归实现
1.思路
- 沿着树的深度优先探索节点,先访问根节点,然后递归地访问左子树和右子树(对于二叉树)。可用于遍历树、计算节点值、查找特定节点等。
2.经典案例
- 在二叉树的前序遍历(LeetCode 144. 二叉树的前序遍历)中,先访问根节点,再递归前序遍历左子树,最后递归前序遍历右子树。
2.广度优先搜索(BFS) - 队列实现
1.思路
- 按树的层次逐层访问节点,使用队列辅助实现。先将根节点入队,每次从队列取出一个节点,访问它并将其孩子节点入队,直到队列为空。常用于按层遍历树、解决与层次相关的问题。
2.经典案例
- 在二叉树的层序遍历(LeetCode 102. 二叉树的层序遍历)中,通过队列实现按层访问二叉树的所有节点。
4.栈
1.单调栈法
1.思路
- 利用栈维护一个单调递增或递减的序列,通过入栈和出栈操作,解决寻找下一个更大元素、下一个更小元素等问题。
2.经典案例
LeetCode 496. 下一个更大元素 I
- 遍历数组,利用单调栈记录每个元素的下一个更大元素。
LeetCode 84. 柱状图中最大的矩形
- 通过单调栈维护柱子高度,计算柱状图中最大矩形面积。
5.堆
1.堆(优先队列)法
1.思路
- 利用堆的特性维护数据的优先级,通过插入和删除操作,解决前 K 个最大或最小元素、中位数等问题。
2.经典案例:
LeetCode 215. 数组中的第 K 个最大元素
- 使用最小堆获取数组中第 K 个最大元素。
LeetCode 347. 前 K 个高频元素
- 结合哈希表统计频率,利用优先队列(最大堆)获取前 K 个高频元素。
6.通用的算法策略
1.二分查找法
适用场景
- 主要用于有序数组或可转化为有序结构的场景。
算法思路
- 每次将搜索区间缩小一半,通过比较中间元素与目标值的大小关系,决定在左半部分还是右半部分继续搜索,从而快速定位目标元素或满足特定条件的位置。
经典案例
LeetCode 704. 二分查找
- 在有序数组中查找目标值,每次比较中间元素与目标值,缩小搜索范围,直到找到目标值或确定目标值不存在。
LeetCode 33. 搜索旋转排序数组
- 对于旋转排序数组,通过判断中间元素与两端元素的关系,确定有序部分,然后在有序部分进行二分查找。
2.动态规划法
适用场景
- 适用于具有最优子结构和子问题重叠性质的问题,可用于数组、字符串、图等多种数据结构相关问题。
算法思路
- 将复杂问题分解为相互关联的子问题,通过定义状态和状态转移方程,求解子问题并保存其解,避免重复计算,最终得到原问题的解。
经典案例
LeetCode 5. 最长回文子串
- 定义二维状态 dp [i][j] 表示字符串 s 从 i 到 j 是否为回文串,通过状态转移方程和边界条件计算最长回文子串。
LeetCode 70. 爬楼梯
- 定义状态 dp [i] 表示爬到第 i 阶楼梯的方法数,依据状态转移方程和边界条件计算爬到楼顶的方法总数。
3.回溯法
适用场景
- 常用于解决组合、排列、路径搜索等问题,涉及对所有可能情况进行深度优先搜索。
算法思路
- 从初始状态开始,逐步探索所有可能路径。若当前路径不符合要求,则回溯到上一个状态,尝试其他路径,直到找到所有解或满足条件的解。
经典案例
LeetCode 46. 全排列
- 从空排列开始,通过回溯依次添加未使用数字,生成所有全排列。
LeetCode 93. 复原 IP 地址
- 通过在字符串中回溯插入点,将字符串分成 4 段,判断每段合法性,得到所有有效 IP 地址。
4.贪心算法
适用场景
- 适用于具有贪心选择性质的问题,即局部最优选择能导致全局最优解,常见于资源分配、调度等问题。
算法思路
- 在每一步决策中,选择当前状态下的最优解,不考虑整体最优解,期望通过一系列局部最优选择达到全局最优。
经典案例
LeetCode 455. 分发饼干
- 对孩子胃口值和饼干尺寸排序后,从胃口最小孩子和尺寸最小饼干开始匹配,每次选择能满足当前孩子的最小饼干。
LeetCode 122. 买卖股票的最佳时机 II
- 每天判断当前价格与前一天价格,若当前价格高则进行买卖操作累加利润。
5.分治法
适用场景
- 适用于可以分解为若干个规模较小、相互独立且与原问题形式相同的子问题的场景,如树的相关问题、数组划分问题等。
算法思路
- 将问题分解为子问题,递归地解决子问题,然后合并子问题的解得到原问题的解。
经典案例
LeetCode 241. 为运算表达式设计优先级
- 按运算符分割表达式为左右两部分,递归计算左右部分结果,再根据运算符组合结果。
LeetCode 53. 最大子数组和
- 将数组分成左右两部分,分别计算左右部分最大子数组和以及跨越中点的最大子数组和,取三者最大值。