Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

755. Pour Water - Leetcode Solution

Problem Description

The "Pour Water" problem asks you to simulate the process of pouring water droplets onto a landscape represented by an array of integers. Each value in the heights array represents the elevation at that position. You are given:

  • heights: An array of integers representing the terrain elevation.
  • volume: The number of water droplets to pour.
  • k: The index where each droplet is poured.

For each droplet, you must simulate its movement:

  1. Try to move left from k to the lowest possible position (with ties going to the leftmost).
  2. If no lower position is found to the left, try to move right from k to the lowest possible position (with ties going to the rightmost).
  3. If neither left nor right has a lower position, the droplet stays at k.
After pouring all water droplets, return the final heights array.

Constraints:

  • Each droplet is poured one at a time, and each droplet moves independently.
  • The heights array is not modified until a droplet settles.
  • All droplets are poured at the same index k.
  • There is always a valid answer; no need to handle invalid input.

Thought Process

At first glance, the problem seems to require simulating gravity and water flow, which could be complex. However, the rules are specific and deterministic, so we can approach it step by step:

  • For each droplet, we only need to check the lowest point to the left or right of k.
  • We need to be careful to always pick the leftmost (or rightmost) in case of ties when searching for a lower spot.
  • After each droplet lands, we must update the heights array before pouring the next droplet.
  • Brute-force would involve, for each droplet, scanning left and right from k to find the appropriate location. This is acceptable given the constraints, but we can think about optimizations later.

The key is to simulate each droplet independently, always starting from k, and updating the terrain after each pour.

Solution Approach

Let's break down the algorithm step-by-step:

  1. For each droplet (repeat volume times):
    • Start at index k.
    • Move Left:
      • From k-1 to 0, move as long as the next position is lower than the current.
      • If a position is equal, continue; if higher, stop.
      • Keep track of the leftmost lowest position found.
    • If a lower position was found to the left:
      • Place the droplet there (heights[pos] += 1), then continue to the next droplet.
    • If not, Move Right:
      • From k+1 to n-1, move as long as the next position is lower than the current.
      • Keep track of the rightmost lowest position found.
    • If a lower position was found to the right:
      • Place the droplet there (heights[pos] += 1), then continue.
    • If neither left nor right has a lower position:
      • Place the droplet at k (heights[k] += 1).
  2. Return the modified heights array.

We use simple loops for left and right searches. There are possible optimizations using stacks or caching, but the above is efficient enough for typical constraints.

Example Walkthrough

Example:
heights = [2,1,1,2,1,2,2], volume = 4, k = 3

  1. First droplet:
    • Start at index 3 (height 2).
    • Left: index 2 (height 1) is lower. Move to index 2.
    • Left: index 1 (height 1) is equal, but not lower. Stop.
    • Land at index 2. heights = [2,1,2,2,1,2,2]
  2. Second droplet:
    • Start at index 3 (height 2).
    • Left: index 2 (height 2) is not lower. Stop.
    • Right: index 4 (height 1) is lower. Move to index 4.
    • Land at index 4. heights = [2,1,2,2,2,2,2]
  3. Third droplet:
    • Start at index 3 (height 2).
    • Left: index 2 (height 2) is not lower. Stop.
    • Right: index 4 (height 2) is not lower. Stop.
    • Land at index 3. heights = [2,1,2,3,2,2,2]
  4. Fourth droplet:
    • Start at index 3 (height 3).
    • Left: index 2 (height 2) is lower. Move to index 2.
    • Left: index 1 (height 1) is lower. Move to index 1.
    • Land at index 1. heights = [2,2,2,3,2,2,2]

Final answer: [2,2,2,3,2,2,2]

Time and Space Complexity

Brute-force Approach:

  • For each droplet (up to volume), we may scan the entire heights array left and right from k.
  • Time Complexity: O(volume * n), where n is the length of heights.
  • Space Complexity: O(1) extra space (in-place modification).
Optimized Approaches:
  • With careful caching or using a stack to track valleys, we could sometimes do better, but the above is sufficient for reasonable constraints.

Summary

In summary, the Pour Water problem is a simulation task where each droplet is poured at a specified index and moves to the lowest adjacent position, preferring the leftmost or rightmost in case of ties. The key insight is to simulate each droplet independently, always updating the terrain after each pour. The step-by-step search left and right ensures correctness and is efficient for typical input sizes. This approach is clear, robust, and easy to implement.

Code Implementation

class Solution:
    def pourWater(self, heights, volume, k):
        n = len(heights)
        for _ in range(volume):
            pos = k
            # Try to move left
            for i in range(k-1, -1, -1):
                if heights[i] < heights[pos]:
                    pos = i
                elif heights[i] > heights[pos]:
                    break
            if pos != k:
                heights[pos] += 1
                continue
            # Try to move right
            pos = k
            for i in range(k+1, n):
                if heights[i] < heights[pos]:
                    pos = i
                elif heights[i] > heights[pos]:
                    break
            if pos != k:
                heights[pos] += 1
                continue
            # Stay at k
            heights[k] += 1
        return heights
      
class Solution {
public:
    vector<int> pourWater(vector<int>& heights, int volume, int k) {
        int n = heights.size();
        for (int v = 0; v < volume; ++v) {
            int pos = k;
            // Move left
            for (int i = k - 1; i >= 0; --i) {
                if (heights[i] < heights[pos])
                    pos = i;
                else if (heights[i] > heights[pos])
                    break;
            }
            if (pos != k) {
                heights[pos]++;
                continue;
            }
            // Move right
            pos = k;
            for (int i = k + 1; i < n; ++i) {
                if (heights[i] < heights[pos])
                    pos = i;
                else if (heights[i] > heights[pos])
                    break;
            }
            if (pos != k) {
                heights[pos]++;
                continue;
            }
            // Stay at k
            heights[k]++;
        }
        return heights;
    }
};
      
class Solution {
    public int[] pourWater(int[] heights, int volume, int k) {
        int n = heights.length;
        for (int v = 0; v < volume; ++v) {
            int pos = k;
            // Move left
            for (int i = k - 1; i >= 0; --i) {
                if (heights[i] < heights[pos])
                    pos = i;
                else if (heights[i] > heights[pos])
                    break;
            }
            if (pos != k) {
                heights[pos]++;
                continue;
            }
            // Move right
            pos = k;
            for (int i = k + 1; i < n; ++i) {
                if (heights[i] < heights[pos])
                    pos = i;
                else if (heights[i] > heights[pos])
                    break;
            }
            if (pos != k) {
                heights[pos]++;
                continue;
            }
            // Stay at k
            heights[k]++;
        }
        return heights;
    }
}
      
var pourWater = function(heights, volume, k) {
    const n = heights.length;
    for (let v = 0; v < volume; ++v) {
        let pos = k;
        // Move left
        for (let i = k - 1; i >= 0; --i) {
            if (heights[i] < heights[pos])
                pos = i;
            else if (heights[i] > heights[pos])
                break;
        }
        if (pos !== k) {
            heights[pos]++;
            continue;
        }
        // Move right
        pos = k;
        for (let i = k + 1; i < n; ++i) {
            if (heights[i] < heights[pos])
                pos = i;
            else if (heights[i] > heights[pos])
                break;
        }
        if (pos !== k) {
            heights[pos]++;
            continue;
        }
        // Stay at k
        heights[k]++;
    }
    return heights;
};