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:
- 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.
- 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)) |
4
Time Complexity: (N * M * log(N * M))
Auxiliary Space: O(N * M)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!