1. 算法题解核心思路剖析
最近在LeetCode上刷题时,我发现几道看似不同但实则存在内在联系的题目。这些题目涵盖了二分查找、滑动窗口等经典算法技巧,非常适合用来训练算法思维。今天我就来详细拆解这些题目的解题思路,分享一些实战中的心得体会。
2. 供暖器问题(475. Heaters)
2.1 问题描述与直观理解
供暖器问题要求我们找到能够覆盖所有房屋的最小加热半径。给定房屋和供暖器的位置数组,我们需要确定一个最小的半径,使得每个房屋都能被至少一个供暖器覆盖。
这个问题可以转化为:对于每个房屋,找到离它最近的供暖器,然后所有房屋的这个最小距离中的最大值就是我们需要的结果。
2.2 排序与双指针解法
最直接的解法是先对两个数组排序,然后用双指针遍历:
- 对houses和heaters数组进行排序
- 初始化指针i和j,分别指向houses和heaters的起始位置
- 对于每个房屋,找到离它最近的左右两个供暖器
- 取这两个距离中的较小值作为该房屋的覆盖半径
- 最终结果是所有房屋覆盖半径的最大值
时间复杂度分析:排序需要O(mlogm + nlogn),遍历需要O(m+n),因此总时间复杂度为O(mlogm + nlogn)。
2.3 二分查找优化思路
这个问题也可以使用二分查找来解决:
- 先对heaters排序
- 对于每个house,用二分查找找到最近的heater
- 记录所有house的最小覆盖距离的最大值
这种方法的优势在于当houses数量远大于heaters时效率更高。
3. 爱吃香蕉的狒狒(LCR 073. 狒狒吃香蕉)
3.1 问题转化与理解
这道题要求我们找到狒狒吃香蕉的最小速度K,使得它能在H小时内吃完所有香蕉。关键在于理解:
- 吃香蕉的速度K越大,所需时间越少
- 我们需要找到满足time <= H的最小K值
3.2 二分答案法的应用
这是一个典型的"二分答案"问题:
- 确定搜索范围:最小速度是1,最大速度是max(piles)
- 对于每个中间值mid,计算吃完所有香蕉需要的时间
- 如果时间<=H,尝试更小的速度;否则尝试更大的速度
实现时需要注意:
- 计算时间时要对每堆香蕉取上界
- 终止条件是left <= right
3.3 时间复杂度分析
二分查找的时间复杂度是O(log(max(piles))),每次计算需要O(n)时间,因此总时间复杂度为O(nlog(max(piles)))。
4. 分割数组的最大值(410. Split Array Largest Sum)
4.1 问题本质分析
这道题要求将数组分成m个连续子数组,使得这些子数组和的最大值最小。这实际上也是一个"最小化最大值"的问题,与狒狒吃香蕉问题类似。
4.2 二分答案法的再次应用
我们可以使用类似的二分法:
- 确定搜索范围:左边界是数组最大值,右边界是数组总和
- 对于每个中间值mid,计算可以将数组分成多少个子数组
- 如果子数组数量<=m,尝试更小的mid;否则尝试更大的mid
4.3 贪心验证函数
关键在于如何计算给定mid值时的子数组数量:
- 初始化当前和与计数器
- 遍历数组,累加元素
- 当和超过mid时,分割数组并重置当前和
- 最后返回分割数量
5. 无重复字符的最长子串(3. Longest Substring Without Repeating Characters)
5.1 滑动窗口基本思想
这道题要求找到不含重复字符的最长子串长度。滑动窗口是解决这类子串问题的利器。
基本思路:
- 使用哈希集合记录窗口中的字符
- 维护左右指针表示窗口边界
- 当遇到重复字符时,移动左指针直到消除重复
5.2 优化实现细节
实际编码时需要注意:
- 可以直接用哈希表记录字符及其索引,这样遇到重复时可以快速移动左指针
- 窗口大小是right-left+1
- 时间复杂度为O(n),空间复杂度为O(min(m,n)),其中m是字符集大小
6. 长度最小的子数组(209. Minimum Size Subarray Sum)
6.1 滑动窗口的变种应用
这道题要求找到和≥target的最短连续子数组。虽然也是滑动窗口,但与前一题有所不同:
- 窗口扩展条件:当前和<target
- 窗口收缩条件:当前和≥target
6.2 实现要点
关键实现细节:
- 初始化窗口左右边界和当前和
- 移动右边界扩展窗口,累加元素
- 当和≥target时,尝试移动左边界缩小窗口
- 记录满足条件的最小窗口大小
7. 存在重复元素系列问题
7.1 存在重复元素II(219. Contains Duplicate II)
这道题要求判断是否存在两个相同元素,其索引差不超过k。
解法思路:
- 使用哈希表记录元素及其最近出现的位置
- 遍历数组,检查当前元素是否在哈希表中且索引差≤k
- 更新哈希表中当前元素的位置
7.2 存在重复元素III(220. Contains Duplicate III)
这道题更复杂,要求判断是否存在两个元素,其值差≤t且索引差≤k。
解法思路:
- 使用滑动窗口维护大小为k的窗口
- 对于每个元素,检查窗口中是否存在值在[x-t, x+t]范围内的元素
- 可以使用TreeSet等数据结构高效查询
8. 算法技巧总结与实战心得
8.1 二分查找的应用场景
二分查找不仅适用于有序数组查找,还适用于"最小化最大值"或"最大化最小值"这类问题。关键点:
- 确定搜索范围
- 设计验证函数
- 处理边界条件
8.2 滑动窗口的变种
滑动窗口适用于子串/子数组问题,常见变种:
- 固定大小窗口
- 可变大小窗口(如最长无重复子串)
- 带条件窗口(如最小和子数组)
8.3 实战编码技巧
在实现这些算法时,我发现以下技巧很有帮助:
- 先写出暴力解法,再考虑优化
- 画图辅助理解窗口移动过程
- 使用合适的数据结构(如哈希表、TreeSet)
- 注意边界条件处理(如空输入、单个元素等)
在实际面试中,解释清楚思路比直接写代码更重要。建议先说明算法选择理由,再逐步实现。对于二分查找问题,要特别注意终止条件和中间值计算,避免死循环。
