leetcode
leetcode 2851 ~ 2900
直方图的水量

直方图的水量

难度:

标签:

题目描述

Imagine a histogram (bar graph). Design an algorithm to compute the volume of water it could hold if someone poured water across the top. You can assume that each histogram bar has width 1.

The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of water (blue section) are being trapped. Thanks Marcos for contributing this image!

Example:

Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

代码结果

运行时间: 29 ms, 内存: 16.6 MB


/*
 * 思路:
 * 1. 使用 Java Stream 来计算 leftMax 和 rightMax 数组。
 * 2. 通过流的操作来遍历数组并计算每个位置能存储的水量。
 */
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Solution {
    public int trap(int[] height) {
        if (height == null || height.length == 0) return 0;
        int n = height.length;
        int[] leftMax = new int[n];
        int[] rightMax = new int[n];
        leftMax[0] = height[0];
        IntStream.range(1, n).forEach(i -> leftMax[i] = Math.max(leftMax[i - 1], height[i]));
        rightMax[n - 1] = height[n - 1];
        IntStream.iterate(n - 2, i -> i >= 0, i -> i - 1).forEach(i -> rightMax[i] = Math.max(rightMax[i + 1], height[i]));
        return IntStream.range(0, n).map(i -> Math.min(leftMax[i], rightMax[i]) - height[i]).sum();
    }
}

解释

方法:

此题解采用双指针法计算直方图中的水量。初始化两个指针,left指向数组的起始位置,right指向数组的结束位置。同时,设置两个变量leftmax和rightmax来记录从左侧和右侧遍历时遇到的最大高度。通过比较两个指针所指向的高度,决定是移动left指针还是right指针。若height[left]小于height[right],检查当前left指向的高度是否大于leftmax;如果大于,更新leftmax;否则,计算leftmax和当前高度的差值加到结果res中,表示这部分可以积水的量。同理,若height[right]小于或等于height[left],则检查right指向的高度与rightmax,并作类似处理。这样,直到left与right指针相遇,遍历结束,得到总的积水量。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在双指针法中,当height[left] < height[right]时只移动left指针,而当height[right] <= height[left]时只移动right指针?这种选择有何算法逻辑上的依据?
这种选择的关键在于保证在移动指针时能够确定积水的边界。当height[left] < height[right]时,可以确定左侧的界定边界(leftmax)是有效的,因为即使右侧存在更高的边界,它也不会影响左侧已经确定的积水界限。因此,可以安全地移动left指针,来更新或计算该位置的积水情况。相反,当height[right] <= height[left]时,右侧边界(rightmax)是可靠的,因为左侧的高度不会影响右侧的积水计算。这样的处理确保了在每一步中都能通过leftmax或rightmax准确计算积水量,而不需要担心另一侧可能的更高边界。
🦆
在实现中,leftmax和rightmax被初始化为-1,这是否意味着该算法假定所有的直方图高度都是非负的?如果数组中存在负值,这种方法是否仍然有效?
是的,初始化leftmax和rightmax为-1的确是基于所有直方图高度是非负值的假定。在现实应用中,直方图高度通常代表物理量度如水位或物体的高度,因此通常是非负的。如果直方图中存在负值,则该算法可能不适用,因为它在计算积水量时是基于高度差(leftmax和rightmax与当前高度的差值)来计算的,这在高度为负时逻辑上会出现问题。
🦆
题解中提到的累加积水量的计算方法是基于leftmax和rightmax与当前高度的差值。这种计算是否考虑了两边高度不一致的情况,即一边远高于另一边时?
是的,该计算方法考虑了两边高度不一致的情况。通过双指针法和leftmax以及rightmax的更新机制,算法确保了不论两边的高度差异如何,都可以正确地计算出每个位置可能的积水量。当某一端明显高于另一端时,更高的一端的最大值(leftmax或rightmax)会控制积水的最大可能量,而较低的一端则逐步更新其最大值并计算差值作为积水量。这种处理方式允许算法在处理非均匀高度分布时仍然能够准确地计算出积水总量。

相关问题