返回

从单调栈到双指针,巧解 LeetCode 42. 接雨水!

闲谈







**前言** 

在 LeetCode 42. 接雨水的题目中,我们被给定一个表示柱状图的非负整数数组,每个柱子的宽度为 1,高度由数组中的值表示。目标是计算出在柱状图中能接住多少雨水。

**方法一:单调栈** 

单调栈是一种先进后出的数据结构,其特点是栈顶元素始终保持单调性。对于本题,我们可以使用单调递减栈来解决。

具体步骤如下:

1. 从左到右遍历柱状图。
2. 若当前柱子高度大于栈顶元素,则将当前柱子入栈。
3. 否则,从栈中弹出元素,直到栈顶元素小于当前柱子高度。
4. 对于每个弹出的元素,计算其能接住的雨水量,并累加到总雨水量中。

**方法二:双指针** 

双指针是一种高效的数据结构,其核心思想是使用两个指针从数组两端向中间移动。对于本题,我们可以使用双指针来解决。

具体步骤如下:

1. 初始化两个指针 `left` 和 `right`,分别指向柱状图的最左端和最右端。
2. 移动指针 `left` 和 `right`,找到当前左右两侧的最大柱子高度 `max_left` 和 `max_right`。
3. 计算当前能接住的雨水量:`min(max_left, max_right) - 当前柱子高度`。
4. 移动指针 `left` 或 `right`,指向较小的那一侧,并更新 `max_left` 或 `max_right`。
5. 重复步骤 2-4,直到 `left` 和 `right` 相遇。

**代码示例** 

```python
# 单调栈方法
def trap_rain_water_stack(heights):
    stack = []
    total_water = 0
    for i, height in enumerate(heights):
        while stack and height > heights[stack[-1]]:
            top = stack.pop()
            if not stack:
                break
            left = stack[-1]
            total_water += (min(height, heights[left]) - heights[top]) * (i - left - 1)
        stack.append(i)
    return total_water

# 双指针方法
def trap_rain_water_two_pointers(heights):
    left, right = 0, len(heights) - 1
    max_left, max_right = heights[left], heights[right]
    total_water = 0
    while left < right:
        if max_left < max_right:
            left += 1
            max_left = max(max_left, heights[left])
            total_water += max_left - heights[left]
        else:
            right -= 1
            max_right = max(max_right, heights[right])
            total_water += max_right - heights[right]
    return total_water

总结

单调栈和双指针都是解决 LeetCode 42. 接雨水 这道经典题目的有效方法。单调栈利用了单调性的特点,而双指针则利用了双向移动的思想,各有优劣。对于不同规模的输入,不同的方法可能表现出不同的效率。在实际应用中,可以根据具体情况选择合适的方法。