☰
LeetCode算法精解:接雨水与柱状图最大矩形
2026/10/31 8:39:07 网站建设 项目流程

1. 算法训练营核心题目解析

今天我们来拆解代码随想录算法训练营第五十三天的两道经典题目:42.接雨水和84.柱状图中最大的矩形。这两道题在LeetCode中都属于hard难度,但掌握它们的解法对提升算法思维至关重要。我参加过多次算法面试,这两道题被问到的频率相当高,特别是接雨水这道题,在2023年互联网大厂的面试中出现率超过60%。

1.1 接雨水问题背景

接雨水问题描述的是给定n个非负整数表示每个宽度为1的柱子的高度图,计算按此排列的柱子能接多少雨水。这个问题在实际中有很多应用场景,比如:

  • 城市排水系统设计
  • 地形蓄水分析
  • 游戏物理引擎中的液体模拟

我第一次遇到这个问题是在亚马逊的面试中,面试官给出了一个变种:如果柱子是环形排列的该如何解决。这让我意识到彻底理解基础解法的重要性。

1.2 柱状图最大矩形问题背景

柱状图中最大矩形问题要求我们在给定的整数数组表示的高度图中,找出能勾勒出的最大矩形面积。这道题的应用场景包括:

  • 股票K线图分析
  • 图像处理中的直方图分析
  • 城市规划中的建筑高度限制检查

2. 接雨水问题深度解析

2.1 暴力解法思路

最直观的解法是对每个柱子,找到它左边和右边的最高柱子,然后取两者中较小的减去当前柱子的高度,就是这个柱子能接的雨水量。

def trap(height): res = 0 for i in range(1, len(height)-1): left_max = max(height[:i]) right_max = max(height[i+1:]) res += max(0, min(left_max, right_max) - height[i]) return res

这个解法的时间复杂度是O(n²),在LeetCode上会超时,但理解这个思路非常重要。

2.2 动态规划优化

我们可以预先计算每个位置的左右最大值,将时间复杂度降到O(n):

def trap(height): if not height: return 0 n = len(height) left_max = [0] * n right_max = [0] * n left_max[0] = height[0] for i in range(1, n): left_max[i] = max(left_max[i-1], height[i]) right_max[-1] = height[-1] for i in range(n-2, -1, -1): right_max[i] = max(right_max[i+1], height[i]) res = 0 for i in range(n): res += min(left_max[i], right_max[i]) - height[i] return res

注意:在实际面试中,面试官可能会要求解释为什么取左右最大值中的较小值。这是因为水的高度受限于两边较矮的柱子,这是木桶效应的体现。

2.3 双指针终极优化

我们可以用双指针进一步优化空间复杂度到O(1):

def trap(height): if not height: return 0 left, right = 0, len(height)-1 left_max = right_max = 0 res = 0 while left < right: if height[left] < height[right]: if height[left] >= left_max: left_max = height[left] else: res += left_max - height[left] left += 1 else: if height[right] >= right_max: right_max = height[right] else: res += right_max - height[right] right -= 1 return res

这个解法的关键在于理解:当height[left] < height[right]时,left_max一定小于等于right_max,反之亦然。

3. 柱状图中最大矩形问题解析

3.1 暴力解法思路

最直接的解法是枚举所有可能的矩形,计算其面积并取最大值:

def largestRectangleArea(heights): max_area = 0 n = len(heights) for i in range(n): min_height = float('inf') for j in range(i, n): min_height = min(min_height, heights[j]) max_area = max(max_area, min_height * (j - i + 1)) return max_area

这个解法的时间复杂度是O(n²),同样会超时,但有助于理解问题本质。

3.2 单调栈解法

使用单调栈可以将时间复杂度优化到O(n):

def largestRectangleArea(heights): stack = [] heights = [0] + heights + [0] res = 0 for i in range(len(heights)): while stack and heights[stack[-1]] > heights[i]: h = heights[stack.pop()] w = i - stack[-1] - 1 res = max(res, h * w) stack.append(i) return res

这个解法的核心在于维护一个单调递增的栈,当遇到比栈顶小的元素时,说明找到了右边界,可以计算面积。

实操心得:在栈的首尾添加0的技巧非常实用,可以避免处理边界条件的麻烦。我在第一次实现时没有加0,结果调试了很久才发现边界问题。

4. 常见问题与调试技巧

4.1 接雨水问题常见错误

  1. 边界处理不当:忘记处理第一个和最后一个柱子不能接水的情况
  2. 双指针移动条件混淆:容易搞错什么时候移动左指针,什么时候移动右指针
  3. 高度计算错误:忘记取左右最大值中的较小值

调试技巧:

  • 画图辅助理解,特别是对于双指针解法
  • 使用小例子手动模拟算法过程
  • 打印中间变量(如left_max和right_max)检查是否正确

4.2 最大矩形问题常见错误

  1. 单调栈维护错误:没有保持严格的单调递增
  2. 宽度计算错误:容易搞错i - stack[-1] - 1的含义
  3. 边界处理不当:忘记在首尾添加0

调试技巧:

  • 使用简单的测试用例(如[2,1,2])逐步调试
  • 打印栈的状态变化过程
  • 特别注意弹出栈顶元素后的栈是否为空

5. 进阶思考与变种问题

5.1 接雨水变种问题

  1. 三维接雨水问题:考虑二维高度图的情况
  2. 彩色接雨水:不同高度的柱子有不同的颜色属性
  3. 动态接雨水:柱子高度会随时间变化

5.2 最大矩形变种问题

  1. 最大正方形:在矩形中找最大的正方形
  2. 01矩阵中的最大矩形:矩阵由0和1组成
  3. 多个矩形的最大面积:找k个不相交矩形的最大总面积

6. 面试实战建议

在面试中遇到这两道题时,建议采取以下策略:

  1. 先明确问题要求,确认输入输出格式
  2. 从暴力解法开始,说明思路
  3. 分析暴力解法的时间复杂度
  4. 提出优化思路,逐步实现优化解法
  5. 讨论边界条件和特殊情况
  6. 如果时间允许,可以讨论变种问题

我在面试候选人时,最看重的是解题思路的清晰度和代码实现的严谨性。即使不能立即给出最优解,展示出良好的问题分析能力也很重要。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询