返回

从接雨水问题看双指针的妙用

前端

在接雨水中运用双指针算法:一个高效的解决方案

引言

想象一下一场倾盆大雨,它在竖立的柱子之间形成了一片水池。如何计算出在这个水池中积攒了多少雨水?这就是著名的 LeetCode 42. 接雨水问题的核心。乍一看,这个问题似乎很复杂,但使用一个巧妙的算法——双指针算法,我们可以巧妙地解决它。

传统方法:动态规划

最直接的方法是使用动态规划。我们从左到右遍历柱子,并计算每根柱子上可能积聚的雨水量。为了做到这一点,我们需要知道该柱子左边和右边最高柱子的高度。通过比较这些高度,我们可以推导出该柱子上方的可容纳雨水量。

这种方法虽然直观,但它的效率不高。它需要遍历柱子两次,一次从左到右,一次从右到左。因此,它的时间复杂度为 O(n),其中 n 是柱子的数量。

双指针算法:一个优化解决方案

双指针算法提供了一种更有效的方法。它使用两个指针同时从两端遍历柱子。

一个指针从左向右移动,而另一个指针从右向左移动。当两个指针相遇时,它们之间的柱子可以容纳的雨水量就是它们之间较低柱子的高度乘以两指针之间的距离。

然后,我们移动指针,让较低指针指向下一个柱子,并继续计算雨水量。通过这种方式,我们可以只遍历柱子一次,将时间复杂度降低到 O(n)。

Python 实现

以下是用 Python 实现的双指针算法:

def trap(height):
    left, right = 0, len(height) - 1
    max_left, max_right = 0, 0
    rainwater = 0
    
    while left < right:
        if height[left] < height[right]:
            if height[left] > max_left:
                max_left = height[left]
            else:
                rainwater += max_left - height[left]
            left += 1
        else:
            if height[right] > max_right:
                max_right = height[right]
            else:
                rainwater += max_right - height[right]
            right -= 1
    
    return rainwater

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

结论

双指针算法是一个强大的工具,可用于解决各种问题。在 LeetCode 42. 接雨水中,它让我们能够以最佳效率计算出积聚的雨水量。通过利用双指针的协同作用,我们可以巧妙地优化传统方法,从而获得卓越的性能。

常见问题解答

  1. 为什么双指针算法比动态规划快?

    • 双指针算法只遍历柱子一次,而动态规划需要遍历两次。
  2. 双指针算法如何处理相邻柱子高度相等的情况?

    • 这种情况不会影响算法,因为雨水量仅取决于较低柱子的高度。
  3. 如果柱子的高度都很低,算法是否仍然有效?

    • 是的,算法仍然有效,但积聚的雨水量会更少。
  4. 如果柱子的高度非常高,算法是否会失败?

    • 不,算法不会失败,但它可能需要更多时间才能完成计算。
  5. 还有什么其他问题可以使用双指针算法解决?

    • 求两条曲线之间的面积、寻找数组中的最大子数组、计算回文子串的数量等。