Trapping Rain Water

Updated on 01 July, 2025
Trapping Rain Water header image

Problem Statement

The problem involves an array of non-negative integers wherein each element represents the height of a bar in an elevation map. Each bar has a unit width of 1. After a rain, water can get trapped between these bars. The goal is to calculate the total volume of water that remains trapped between the bars after it stops raining. The trapping of water here is influenced by the heights of surrounding bars; water will remain trapped in a trough if there are taller or equal bars on both sides of the trough.

Examples

Example 1

Input:

height = [0,1,0,2,1,0,1,3,2,1,2,1]

Output:

6

Explanation:

The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.

Example 2

Input:

height = [4,2,0,3,2,5]

Output:

9

Constraints

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

Approach and Intuition

  1. The key concept here is to understand how water can get trapped between bars:
    • Water gets trapped when a bar is surrounded by taller bars on both sides. The trapped water above each bar is determined by the height of the smaller of the two boundary bars (left and right side) minus the height of the current bar.
  2. From the examples:
    • In the first example, the elevation array is [0,1,0,2,1,0,1,3,2,1,2,1]. We can visually analyze how water can be trapped in different troughs made up by consecutive bars. A detailed understanding points out that there are pockets at various points where water is trapped.
    • For the second example, the elevation array [4,2,0,3,2,5] makes it evident that water will trap in the mid-section where lower height bars are flanked by taller bars at both ends.
  3. The constraints indicate that the length of the height array can go up to 20,000, which suggests that a time-efficient approach is necessary due to potentially large input sizes.
  4. Using two-pointer technique can be effective here:
    • Initialize two pointers at both ends of the array.
    • Compare the heights at these pointers, move the pointer pointing to the shorter bar inward, and at each step calculate if water can be trapped above the current bar based on previously seen bars.
  5. The computational challenge is manageable by:
    • Ensuring that at each step, water trapping is checked through a local relative minimum which gets updated as we move our pointers from both ends to the middle.
  6. This approach effectively reduces the problem to linear time complexity, hence tackling the upper constraint limit efficiently. The actual implementation would involve maintaining a running tally of maximum height bars seen from both ends and calculating trapped water bar by bar as the pointers approach each other.

Solutions

  • C++
  • Java
  • C
  • JavaScript
  • Python
cpp
class Solution {
public:
    int trapRainWater(vector<int>& heights) {
        int leftPtr = 0, rightPtr = heights.size() - 1;
        int totalWater = 0;
        int maxLeft = 0, maxRight = 0;
        while (leftPtr < rightPtr) {
            if (heights[leftPtr] < heights[rightPtr]) {
                heights[leftPtr] >= maxLeft ? (maxLeft = heights[leftPtr])
                                            : totalWater += (maxLeft - heights[leftPtr]);
                ++leftPtr;
            } else {
                heights[rightPtr] >= maxRight ? (maxRight = heights[rightPtr])
                                              : totalWater += (maxRight - heights[rightPtr]);
                --rightPtr;
            }
        }
        return totalWater;
    }
};

Here's a solution summary for the trapping rain water problem using C++:

The given C++ code defines a member function trapRainWater within the Solution class. This function is intended to calculate the total amount of water that can be trapped between bars in a list of given heights (which can be visualized similar to a histogram).

The function efficiently follows these steps:

  1. Initialize two pointer variables, leftPtr and rightPtr, to point at the beginning and the end of the heights vector respectively. Also, initialize totalWater, maxLeft, and maxRight to zero. These will hold the total water trapped, maximum height encountered from left to right, and maximum height from right to left, respectively.

  2. Use a while loop to iterate as long as leftPtr is less than rightPtr. Within each iteration, compare the heights at these pointers:

    • If the height at leftPtr is less than or equal to the height at rightPtr, compare the height at leftPtr with maxLeft. If it's greater or equal, update maxLeft to this new height. Otherwise, add the difference between maxLeft and the current height to totalWater, then increment leftPtr to move right.

    • If the height at rightPtr is less than the height at leftPtr, undertake a similar approach by comparing rightPtr's height with maxRight. Update maxRight if necessary, or calculate water trapped and then decrement rightPtr to move left.

  3. After the loop, the value of totalWater will be the total unit of water that can be trapped by the bars represented by heights.

This approach ensures a time complexity of O(n) as each height is processed once, which makes it efficient and suitable for large input sizes. The use of two pointers here optimizes the process by eliminating the need for auxiliary space, which would be required in a naïve approach for storing left and right maximums for each index.

java
public class Solution {
    public int calculateWater(int[] elevation) {
        int start = 0, end = elevation.length - 1;
        int waterTrapped = 0;
        int maxLeft = 0, maxRight = 0;
        while (start < end) {
            if (elevation[start] < elevation[end]) {
                maxLeft = Math.max(maxLeft, elevation[start]);
                waterTrapped += maxLeft - elevation[start];
                start++;
            } else {
                maxRight = Math.max(maxRight, elevation[end]);
                waterTrapped += maxRight - elevation[end];
                end--;
            }
        }
        return waterTrapped;
    }
}

This solution efficiently calculates the total amount of water trapped between bars on a histogram using an array of integers that represent the height of each bar. The problem is commonly referred to as "Trapping Rain Water", and the Java code provided is an embodiment of a two-pointer technique that optimizes the time complexity to O(n), where n refers to the number of bars/elevation points.

  • Initialize start to the beginning index of the elevation array and end to the last index. These two pointers will help traverse the array from both ends.
  • Initialize waterTrapped to zero to maintain a running total of trapped water.
  • Set maxLeft and maxRight to zero. These variables will record the maximum heights encountered from the left and right sides respectively.
  • Use a while loop to iterate while start is less than end:
    • If the elevation at start is less than the elevation at end, update maxLeft to the greater value between maxLeft and the elevation at start. Calculate the water trapped at start by subtracting the elevation at start from maxLeft, and add this difference to waterTrapped. Increment start to move right.
    • If the elevation at start is not less than at end, handle the end pointer similarly but in the opposite direction. Update maxRight and subtract the elevation at end from it, adding the difference to waterTrapped. Decrement end to move left.
  • The function returns waterTrapped as the result, which is the total amount of water that can be trapped.

This approach takes advantage of the properties of water trapping where water at a particular point depends on the lesser of maximum heights to its left and right. The two-pointer technique ensures that the elevation comparisons and updates are efficiently managed for all bars.

c
int water_trap(int* bars, int bar_count) {
    int i = 0, j = bar_count - 1;
    int trapped_water = 0;
    int max_left = 0, max_right = 0;
    while (i < j) {
        if (bars[i] < bars[j]) {
            bars[i] >= max_left ? (max_left = bars[i])
                                : (trapped_water += (max_left - bars[i]));
            ++i;
        } else {
            bars[j] >= max_right ? (max_right = bars[j])
                                 : (trapped_water += (max_right - bars[j]));
            --j;
        }
    }
    return trapped_water;
}

This C program calculates the amount of water that can be trapped between bars of different heights after a rainfall, which is a common computational problem. The given function water_trap uses two pointers approach to efficiently determine the trapped water without needing additional space for storing left and right max values for each bar.

Follow these steps to understand the logic of the program:

  1. Initialize two pointers, i and j, which start at the beginning and the end of the array respectively, and integers to store the total trapped water and the maximum height bars from the left and right (max_left and max_right).
  2. Use a while loop to iterate as long as i is less than j.
  3. Within the loop, compare the bars at pointers i and j.
  4. If bars[i] is less than bars[j], check if bars[i] is greater than or equal to max_left. If true, update max_left to bars[i]. If not, add the difference between max_left and bars[i] to trapped_water and increment i.
  5. If bars[j] is less than or equal to bars[i], apply similar logic as above but for max_right and decrement j.

Once the loop finishes, the trapped_water variable contains the total volume of the trapped water, which the function returns.

This approach ensures a time complexity of O(n) and a space complexity of O(1), which is optimal for this kind of problem. Remember to provide a correct bar_count and valid bars array to ensure accurate computations.

js
var calculateWaterTrap = function (heights) {
    let l = 0,
        r = heights.length - 1;
    let totalWater = 0;
    let maxLeft = 0,
        maxRight = 0;
    while (l < r) {
        if (heights[l] < heights[r]) {
            maxLeft = Math.max(maxLeft, heights[l]);
            totalWater += maxLeft - heights[l];
            l++;
        } else {
            maxRight = Math.max(maxRight, heights[r]);
            totalWater += maxRight - heights[r];
            r--;
        }
    }
    return totalWater;
};

The given JavaScript function calculateWaterTrap determines the amount of water that can be trapped between blocks of varying heights, represented as an array. Below is an overview of how the code achieves this:

  • Initialize two pointers, l (left) and r (right), at the beginning and end of the array.
  • Set totalWater to track the accumulated water, maxLeft to track the maximum height on the left, and maxRight to track the maximum height on the right.
  • While the left pointer does not cross the right:
    1. Compare the heights at the two pointers.
    2. If the height at the left pointer is less than the right:
      • Update maxLeft with the greater value between itself and the height at the left pointer.
      • Add the difference between maxLeft and the height at the left pointer to totalWater.
      • Move the left pointer to the right (increment).
    3. Otherwise:
      • Update maxRight with the greater value between itself and the height at the right pointer.
      • Add the difference between maxRight and the height at the right pointer to totalWater.
      • Move the right pointer to the left (decrement).
  • Return the totalWater value, which gives the total trapped water.

This approach leverages a two-pointer strategy to efficiently solve the problem in linear time, ensuring that each block is visited once to determine the trapped water above it using its left and right maximum heights.

python
class Solution:
    def water_trap(self, bars):
        lo, hi = 0, len(bars) - 1
        water_total = 0
        max_left, max_right = 0, 0
        while lo < hi:
            if bars[lo] < bars[hi]:
                max_left = max(max_left, bars[lo])
                water_total += max_left - bars[lo]
                lo += 1
            else:
                max_right = max(max_right, bars[hi])
                water_total += max_right - bars[hi]
                hi -= 1
        return water_total

The provided Python solution calculates the amount of rainwater trapped between heights represented by an array of integers. The array bars denotes the height of bars at different positions. The function water_trap computes the total volume of trapped water utilizing two pointers and a greedy approach:

  • Initialize two pointers, lo (start) and hi (end), and set them to the bounds of the array.
  • Initialize variables to store the maximum height of bars encountered from the left (max_left) and the right (max_right), and a variable water_total to accumulate the trapped water.
  • Use a while loop to iterate until the two pointers meet. Within each iteration:
    • Compare the height at the two pointers.
    • If the bar on the left (bars[lo]) is lower than the bar on the right (bars[hi]):
      • Update max_left to be the maximum of its current value and the height at location lo.
      • Calculate the trapped water at this position as the difference between max_left and bars[lo], then increment lo.
    • If the bar on the right (bars[hi]) is lower or equal:
      • Similarly, adjust max_right, calculate trapped water for the right position, and decrement hi.
  • Continue this process until all water that can be trapped is accounted for.
  • Return water_total, which now contains the total amount of trapped rainwater.

This method ensures that you efficiently find water trapped between bars in O(n) time complexity and O(1) space, handling each bar at most once.

Comments

No comments yet.