Saturday, September 21, 2024
Google search engine
HomeData Modelling & AITrapping Rain Water in a Matrix

Trapping Rain Water in a Matrix

Given a matrix arr[][] of dimension M*N consisting of positive integers, where arr[i][j] represents the height of each unit cell, the task is to find the total volume of water trapped in the matrix after rain.

Examples:

Input: arr[][] = {{4, 2, 7}, {2, 1, 10}, {5, 10, 2}} 
Output: 1
Explanation:
The rain water can be trapped in the following way:

  1. The cells, {(0, 0), (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1), (2, 2)} traps 0 unit volume of rain water as all water goes out of the matrix as cells are on the boundary.
  2. The cell (2, 2) traps 1 unit volume of rain water in between the cells {(0, 1), (1, 0), (1, 2), and (2, 1)}.

Therefore, a total of 1 unit volume of rain water has been trapped inside the matrix.

Input: arr[][] = {{1, 4, 3, 1, 3, 2}, {3, 2, 1, 3, 2, 4}, {2, 3, 3, 2, 3, 1}}
Output: 4

Approach: The given problem can be solved by using the Greedy Technique and Min-Heap. Follow the steps below to solve the problem:

  • Initialize a Min-Heap using the priority_queue, say PQ, to store the pairs of positions of a cell and its height.
  • Push all the boundary cells in the PQ and mark all the pushed cells as visited.
  • Initialize two variables, say ans as 0 and maxHeight as 0 to store the total volume and the maximum height of all the cells in PQ respectively.
  • Iterate until PQ is not empty and perform the following steps:
    • Store the top node of PQ in a variable, say front, and erase the top element of PQ.
    • Update the value of maxHeight as the maximum of maxHeight and front.height.
    • Now, traverse to all the adjacent nodes of the current cell (front.X, front.Y) and do the following:
      • If the adjacent cell is valid i.e, the cell is not out of bound and not yet visited, then, push the value of the adjacent cell into PQ.
      • If the height of the adjacent cell is less than maxHeight then increment the ans by the difference of maxHeight and the height of the adjacent cell.
  • Finally, after completing the above steps, print the value of ans as the resultant water trapped after rain.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Stores the direction of all the
// adjacent cells
vector<vector<int> > dir
    = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } };
 
// Node structure
struct node {
 
    int height;
    int x, y;
};
 
// Comparator function to implement
// the min heap using priority queue
struct Compare {
 
    // Comparator function
    bool operator()(node const& a, node const& b)
    {
        return a.height > b.height;
    }
};
 
// Function to find the amount of water
// the matrix is capable to hold
int trapRainWater(vector<vector<int> >& heightMap)
{
    int M = heightMap.size();
    int N = heightMap[0].size();
 
    // Stores if a cell of the matrix
    // is visited or not
    vector<vector<bool> > visited(M,
                                  vector<bool>(N, false));
 
    // Initialize a priority queue
    priority_queue<node, vector<node>, Compare> pq;
 
    // Traverse over the matrix
    for (int i = 0; i < M; i++) {
        for (int j = 0; j < N; j++) {
 
            // If element is not on
            // the boundary
            if (!(i == 0 || j == 0 || i == M - 1
                  || j == N - 1))
                continue;
 
            // Mark the current cell
            // as visited
            visited[i][j] = true;
 
            // Node for priority queue
            node t;
            t.x = i;
            t.y = j;
            t.height = heightMap[i][j];
 
            // Pushe all the adjacent
            // node in the pq
            pq.push(t);
        }
    }
 
    // Stores the total volume
    int ans = 0;
 
    // Stores the maximum height
    int max_height = INT_MIN;
 
    // Iterate while pq is not empty
    while (!pq.empty()) {
 
        // Store the top node of pq
        node front = pq.top();
 
        // Delete the top element of pq
        pq.pop();
 
        // Update the max_height
        max_height = max(max_height, front.height);
 
        // Stores the position of the
        // current cell
        int curr_x = front.x;
        int curr_y = front.y;
 
        for (int i = 0; i < 4; i++) {
 
            int new_x = curr_x + dir[i][0];
            int new_y = curr_y + dir[i][1];
 
            // If adjacent cells are out
            // of bound or already visited
            if (new_x < 0 || new_y < 0 || new_x >= M
                || new_y >= N || visited[new_x][new_y]) {
                continue;
            }
 
            // Stores the height of the
            // adjacent cell
            int height = heightMap[new_x][new_y];
 
            // If height of current cell
            // is smaller than max_height
            if (height < max_height) {
 
                // Increment the ans by
                // (max_height-height)
                ans = ans + (max_height - height);
            }
 
            // Define a new node
            node temp;
            temp.x = new_x;
            temp.y = new_y;
            temp.height = height;
 
            // Push the current node
            // in the pq
            pq.push(temp);
 
            // Mark the current cell
            // as visited
            visited[new_x][new_y] = true;
        }
    }
 
    return ans;
}
 
// Driver Code
int main()
{
    vector<vector<int> > arr = { { 1, 4, 3, 1, 3, 2 },
                                 { 3, 2, 1, 3, 2, 4 },
                                 { 2, 3, 3, 2, 3, 1 } };
    cout << trapRainWater(arr);
 
    return 0;
}


Java




// Java Program for above approach
import java.util.*;
 
// Node structure
class node {
  int height;
  int x, y;
}
 
// Comparator function to implement
// the min heap using priority queue
class Compare implements Comparator<node> {
  public int compare(node a, node b) {
    return a.height - b.height;
  }
}
 
class Main {
  // Stores the direction of all the
  // adjacent cells
  static int[][] dir = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } };
 
  // Function to find the amount of water
  // the matrix is capable to hold
  static int trapRainWater(int[][] heightMap) {
    int M = heightMap.length;
    int N = heightMap[0].length;
 
    // Stores if a cell of the matrix
    // is visited or not
    boolean[][] visited = new boolean[M][N];
 
 
    // Initialize a priority queue
    PriorityQueue<node> pq = new PriorityQueue<node>(new Compare());
 
    // Traverse over the matrix
    for (int i = 0; i < M; i++) {
      for (int j = 0; j < N; j++) {
 
        // If element is not on
        // the boundary
        if (!(i == 0 || j == 0 || i == M - 1 || j == N - 1))
          continue;
 
        // Mark the current cell
        // as visited
        visited[i][j] = true;
 
        // Node for priority queue
        node t = new node();
        t.x = i;
        t.y = j;
        t.height = heightMap[i][j];
 
        // Pushe all the adjacent
        // node in the pq
        pq.offer(t);
      }
    }
 
    // Stores the total volume
    int ans = 0;
 
 
    // Stores the maximum height
    int max_height = Integer.MIN_VALUE;
 
    // Iterate while pq is not empty
    while (!pq.isEmpty()) {
 
      // Store the top node of pq
      node front = pq.poll();
 
      // Update the max_height
      max_height = Math.max(max_height, front.height);
 
      // Stores the position of the
      // current cell
      int curr_x = front.x;
      int curr_y = front.y;
 
      for (int i = 0; i < 4; i++) {
 
        int new_x = curr_x + dir[i][0];
        int new_y = curr_y + dir[i][1];
 
        // If adjacent cells are out
        // of bound or already visited
        if (new_x < 0 || new_y < 0 || new_x >= M || new_y >= N || visited[new_x][new_y]) {
          continue;
        }
 
 
        // Stores the height of the
        // adjacent cell
        int height = heightMap[new_x][new_y];
 
        // If height of current cell
        // is smaller than max_height
        if (height < max_height) {
 
 
          // Increment the ans by
          // (max_height-height)
          ans = ans + (max_height - height);
        }
 
        // Define a new node
        node temp = new node();
        temp.x = new_x;
        temp.y = new_y;
        temp.height = height;
 
 
        // Push the current node
        // in the pq
        pq.offer(temp);
 
        // Mark the current cell
        // as visited
        visited[new_x][new_y] = true;
      }
    }
 
    return ans;
  }
 
  // Driver code
  public static void main(String[] args) {
    int[][] arr = { { 1, 4, 3, 1, 3, 2 }, { 3, 2, 1, 3, 2, 4 }, { 2, 3, 3, 2, 3, 1 } };
    System.out.println(trapRainWater(arr));
  }
}
 
// This code is contributed by codebraxnzt


Python3




# Python Code
 
# Stores the direction of all the
# adjacent cells
dir = [[-1, 0], [0, 1], [1, 0], [0, -1]]
 
# Node structure
class Node:
    def __init__(self, height, x, y):
        self.height = height
        self.x = x
        self.y = y
 
# Comparator function to implement
# the min heap using priority queue
class Compare:
    # Comparator function
    def __lt__(self, a, b):
        return a.height > b.height
 
# Function to find the amount of water
# the matrix is capable to hold
def trapRainWater(heightMap):
    M = len(heightMap)
    N = len(heightMap[0])
 
    # Stores if a cell of the matrix
    # is visited or not
    visited = [[False for _ in range(N)] for _ in range(M)]
 
    # Initialize a priority queue
    pq = []
 
    # Traverse over the matrix
    for i in range(M):
        for j in range(N):
 
            # If element is not on
            # the boundary
            if i == 0 or j == 0 or i == M - 1 or j == N - 1:
                visited[i][j] = True
 
                # Node for priority queue
                t = Node(heightMap[i][j], i, j)
 
                # Pushe all the adjacent
                # node in the pq
                pq.append(t)
 
    # Stores the total volume
    ans = 0
 
    # Stores the maximum height
    max_height = float('-inf')
 
    # Iterate while pq is not empty
    while pq:
 
        # Store the top node of pq
        front = pq.pop()
 
        # Update the max_height
        max_height = max(max_height, front.height)
 
        # Stores the position of the
        # current cell
        curr_x = front.x
        curr_y = front.y
 
        for i in range(4):
 
            new_x = curr_x + dir[i][0]
            new_y = curr_y + dir[i][1]
 
            # If adjacent cells are out
            # of bound or already visited
            if new_x < 0 or new_y < 0 or new_x >= M or new_y >= N or visited[new_x][new_y]:
                continue
 
            # Stores the height of the
            # adjacent cell
            height = heightMap[new_x][new_y]
 
            # If height of current cell
            # is smaller than max_height
            if height < max_height:
 
                # Increment the ans by
                # (max_height-height)
                ans += (max_height - height)
 
            # Define a new node
            temp = Node(height, new_x, new_y)
 
            # Push the current node
            # in the pq
            pq.append(temp)
 
            # Mark the current cell
            # as visited
            visited[new_x][new_y] = True
 
    return ans
 
# Driver Code
arr = [[1, 4, 3, 1, 3, 2], [3, 2, 1, 3, 2, 4], [2, 3, 3, 2, 3, 1]]
print(trapRainWater(arr))


C#




using System;
using System.Collections.Generic;
 
class Gfg
{
  // Stores the direction of all the
  // adjacent cells
  static int[] dx = { -1, 0, 1, 0 };
  static int[] dy = { 0, 1, 0, -1 };
 
  static int TrapRainWater(int[][] heightMap)
  {
    int M = heightMap.Length;
    int N = heightMap[0].Length;
 
    var visited = new bool[M, N];
 
    // Initialize a sorted set
    var pq = new SortedSet<(int, int, int)>();
 
    // Traverse over the matrix
    for (int i = 0; i < M; i++)
    {
      for (int j = 0; j < N; j++)
      {
        // If element is not on the boundary
        if (!(i == 0 || j == 0 || i == M - 1 || j == N - 1))
          continue;
 
        // Mark the current cell as visited
        visited[i, j] = true;
 
        // Tuple for sorted set
        var t = (heightMap[i][j], i, j);
 
        // Pushe all the adjacent nodes in the pq
        pq.Add(t);
      }
    }
 
    // Stores the total volume
    int ans = 0;
 
    // Stores the maximum height
    int maxHeight = int.MinValue;
 
    // Iterate while pq is not empty
    while (pq.Count > 0)
    {
      // Store the top node of pq
      var front = pq.Min;
 
      // Delete the top element of pq
      pq.Remove(front);
 
      // Update the maxHeight
      maxHeight = Math.Max(maxHeight, front.Item1);
 
      // Stores the position of the current cell
      int curr_x = front.Item2;
      int curr_y = front.Item3;
 
      for (int i = 0; i < 4; i++)
      {
        int new_x = curr_x + dx[i];
        int new_y = curr_y + dy[i];
 
        // If adjacent cells are out of bound or already visited
        if (new_x < 0 || new_y < 0 || new_x >= M || new_y >= N || visited[new_x, new_y])
          continue;
 
        // Stores the height of the adjacent cell
        int height = heightMap[new_x][new_y];
 
        // If height of current cell is smaller than maxHeight
        if (height < maxHeight)
        {
          // Increment the ans by (maxHeight - height)
          ans = ans + (maxHeight - height);
        }
 
        // Tuple for sorted set
        var temp = (height, new_x, new_y);
 
        // Push the current node in the pq
        pq.Add(temp);
 
        // Mark the current cell as visited
        visited[new_x, new_y] = true;
      }
    }
 
    return ans;
  }
 
  static void Main(string[] args)
  {
    int[][] arr = new int[3][];
    arr[0] = new int[] { 1, 4, 3, 1, 3, 2 };
    arr[1] = new int[] { 3, 2, 1, 3, 2, 4 };
    arr[2] = new int[] { 2, 3, 3, 2, 3, 1 };
 
    Console.WriteLine(TrapRainWater(arr));
  }
}


Javascript




// Define directions array
const dir = [[-1, 0], [0, 1], [1, 0], [0, -1]];
 
// Node structure
class Node {
  constructor(height, x, y) {
    this.height = height;
    this.x = x;
    this.y = y;
  }
}
 
// Comparator function to implement
// the min heap using priority queue
class Compare {
  // Comparator function
  static compare(a, b) {
    return a.height > b.height;
  }
}
 
// Function to find the amount of water
// the matrix is capable to hold
function trapRainWater(heightMap) {
  const M = heightMap.length;
  const N = heightMap[0].length;
 
  // Stores if a cell of the matrix
  // is visited or not
  const visited = new Array(M).fill(false).map(() => new Array(N).fill(false));
 
  // Initialize a priority queue
  const pq = [];
 
  // Traverse over the matrix
  for (let i = 0; i < M; i++) {
    for (let j = 0; j < N; j++) {
      // If element is not on
      // the boundary
      if (i === 0 || j === 0 || i === M - 1 || j === N - 1) {
        visited[i][j] = true;
 
        // Node for priority queue
        const t = new Node(heightMap[i][j], i, j);
 
        // Push all the adjacent
        // node in the pq
        pq.push(t);
      }
    }
  }
 
  // Stores the total volume
  let ans = 0;
 
  // Stores the maximum height
  let max_height = -Infinity;
 
  // Iterate while pq is not empty
  while (pq.length) {
    // Store the top node of pq
    const front = pq.pop();
 
    // Update the max_height
    max_height = Math.max(max_height, front.height);
 
    // Stores the position of the
    // current cell
    const curr_x = front.x;
    const curr_y = front.y;
 
    for (let i = 0; i < 4; i++) {
      const new_x = curr_x + dir[i][0];
      const new_y = curr_y + dir[i][1];
 
      // If adjacent cells are out
      // of bound or already visited
      if (new_x < 0 || new_y < 0 || new_x >= M || new_y >= N || visited[new_x][new_y]) {
        continue;
      }
 
      // Stores the height of the
      // adjacent cell
      const height = heightMap[new_x][new_y];
 
      // If height of current cell
      // is smaller than max_height
      if (height < max_height) {
        // Increment the ans by
        // (max_height-height)
        ans += (max_height - height);
      }
 
      // Define a new node
      const temp = new Node(height, new_x, new_y);
 
      // Push the current node
      // in the pq
      pq.push(temp);
 
      // Mark the current cell
      // as visited
      visited[new_x][new_y] = true;
    }
  }
 
  return ans;
}
 
// Driver Code
const arr = [[1, 4, 3, 1, 3, 2], [3, 2, 1, 3, 2, 4], [2, 3, 3, 2, 3, 1]];
console.log(trapRainWater(arr))


Output

4

Time Complexity: (N * M * log(N * M))
Auxiliary Space: O(N * M)

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments