Efficient Solutions for Trapping Rain Water | Algorithmic Strategies
Problem Statement
Trapping Rain Water:
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.
- Introduction to the Problem
- Underlying Concepts
- Examples and Illustrations
- Brute Force Approach
- Optimization Techniques
- Algorithmic Thinking
- Common Mistakes and Pitfalls
- Coding Best Practices
- Testing and Debugging
- Algorithm Analysis
- Application in Real-world Projects
- Example test cases
- Solution for different languages
- Time and Space Complexity
Introduction to the Problem:
- Problem Statement: Trapping rainwater on an elevation map involves calculating the amount of water trapped between bars representing different elevations. When it rains, water accumulates between these bars, and the task is to determine the total amount of water trapped.
- Input and Output Requirements:
- The input consists of an array of non-negative integers representing the elevation at each position on the map.
- The output is the total amount of water trapped between the bars.
- Real-world Scenario: Understanding this problem is crucial in various real-world scenarios, such as urban drainage systems or architecture design in flood-prone areas.
For example, urban planners need to calculate how much water a drainage system should be able to handle during heavy rainfall to prevent flooding in streets and buildings.
Underlying Concepts:
- Elevation Map: An elevation map is represented by an array of integers where each integer corresponds to the height of a bar on the map. The higher the integer value, the higher the bar's elevation.
- Water Trapping: When it rains on an elevation map, water accumulates between bars of different heights. Water gets trapped in the lower areas between the taller bars, forming "pools" or "lakes" of water. The goal is to calculate the total volume of water trapped between the bars after rainfall.
Examples and Illustrations:
Walkthrough examples: These examples demonstrate how the problem of trapping rainwater can be approached through manual calculations using specific elevation maps.
- Example 1: Consider an elevation map represented by the array [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1].
- Visualize the elevation map.
- Identify the areas where water can be trapped between the bars.
- Calculate the amount of water trapped using manual calculations, following the water trapping process.
- Example 2: Take another elevation map represented by the array [3, 0, 0, 2, 0, 4].
- Visualize the elevation map.
- Identify the areas where water can be trapped between the bars.
- Calculate the amount of water trapped using manual calculations, following the water trapping process.
Visualization:
Brute Force Approach:
- Naive Solution: The naive solution to the "Trapping Rain Water" problem involves iterating through each bar in the elevation map and calculating the amount of water that can be trapped above it.
This is done by finding the maximum heights of bars to the left and right of each bar and computing the minimum of these two heights.
The difference between the minimum height and the height of the current bar gives the amount of water trapped above it. - Complexity Analysis:
The time complexity of the brute force approach is O(n^2), where n is the number of bars in the elevation map. We iterate through each bar and for each bar, we iterate through all bars to its left and right to find the maximum heights.
The space complexity is O(1) as we are not using any additional data structures. However, the approach may involve redundant calculations, resulting in inefficiency.
Optimization Techniques:
- Two Pointer Technique: The Two Pointer Technique optimizes the solution by using two pointers, one starting from the left and one from the right, to determine the maximum height of bars on both sides. This allows for a more efficient calculation of trapped water without the need for a stack or hash table.
- Stack-Based Approach: A stack-based approach can further optimize the solution by using a stack to keep track of the indices of bars in non-decreasing order of their heights.
This helps in efficiently calculating trapped water by iterating through the elevation map only once. - Complexity Analysis: Compare the time and space complexity of the optimized approaches with the brute force approach. The Two Pointer Technique and Stack-Based Approach offer improved time complexity compared to the brute force approach, with both having a time complexity of O(n) and space complexity of O(1). This is because they iterate through the elevation map only once, leading to more efficient calculations of trapped water.
However, the space complexity may vary depending on the implementation details of the stack-based approach.
Algorithmic Thinking:
Divide and Conquer:
- Breaking Down the Problem:
- "Divide and Conquer" involves breaking down a complex problem into simpler subproblems.
- For "Trapping Rain Water," identifying key subproblems such as finding the maximum height of bars on the left and right sides of each bar can simplify the problem-solving process.
- Steps for Divide and Conquer:
- Identify key subproblems within the problem statement.
- Solve each subproblem independently.
- Combine the solutions of subproblems to obtain the overall solution.
- Application to "Trapping Rain Water":
- Identify subproblems like calculating the maximum height of bars on the left and right sides of each bar and determining the amount of water trapped at each position.
- Combine the solutions of these subproblems to calculate the total amount of water trapped.
- Effectiveness:
- "Divide and Conquer" is effective when the problem can be easily divided into smaller, more manageable parts.
- Each subproblem is solved independently, simplifying the overall problem-solving process.
Algorithmic Strategies:
- Introduction:
- Algorithmic strategies involve adopting specific techniques or approaches to tackle problems more efficiently.
- In the context of "Trapping Rain Water," strategies such as dynamic programming, two-pointer technique, and stack-based approach can be considered algorithmic approaches.
- Dynamic Programming:
- Dynamic programming can be applied to efficiently solve the problem by breaking it down into smaller subproblems and storing the results of these subproblems to avoid redundant calculations.
- For "Trapping Rain Water," dynamic programming can be used to calculate the maximum water trapped at each position on the elevation map, considering the water trapped to the left and right of each bar.
- Two-Pointer Technique:
- The Two-Pointer Technique optimizes the solution by using two pointers, one starting from the left and one from the right, to determine the maximum height of bars on both sides.
- This allows for a more efficient calculation of trapped water without the need for a stack or hash table.
- Stack-Based Approach:
- A stack-based approach can further optimize the solution by using a stack to keep track of the indices of bars in non-decreasing order of their heights.
- This helps in efficiently calculating the trapped water by iterating through the elevation map only once.
- Algorithmic Efficiency:
- Algorithmic strategies aim to improve the efficiency of solving problems.
- Dynamic programming, the two-pointer technique, and stack-based approach provide alternative approaches that reduce time complexity and improve the overall efficiency of calculating trapped water.
- Adaptability:
- Algorithmic strategies adapt to various problem scenarios.
- They can be applied to different problems by leveraging the underlying principles of dynamic programming, pointer techniques, and stack-based approaches.
- Problem-Specific Strategy:
- The choice of strategy depends on the problem requirements and constraints.
- Understanding the nature of the "Trapping Rain Water" problem guides the selection of the most appropriate algorithmic strategy for efficient solution.
Common Mistakes and Pitfalls:
- Edge Cases:
- Overlooking the empty elevation Map:
- Mistake: Assuming the elevation map always contains bars.
- Solution: Check for an empty elevation map at the beginning and handle it appropriately to avoid errors.
- Handling Single Bar Elevation Map:
- Mistake: Not considering the case where the elevation map has only one bar.
- Solution: Ensure the algorithm works correctly for elevation maps with one or two bars.
- Extreme elevation values:
- Mistake: Ignoring edge cases with extreme elevation values (e.g., very large or very small integers).
- Solution: Test the algorithm with extreme elevation values to verify its robustness.
- Handling duplicate pairs:
- Ignoring duplicate pairs:
- Mistake: Overlooking duplicate pairs in the elevation map.
- Solution: Account for duplicate pairs and decide whether to include them in the result or not.
- Counting the Same Elements Twice:
- Mistake: Counting the same elevation value twice when considering pairs.
- Solution: Implement a mechanism to avoid pairing an elevation value with itself.
- Handling reverse pairs:
- Mistake: Treating (a, b) and (b, a) as different pairs.
- Solution: Ensure symmetry in pairs and handle reverse pairs appropriately.
- Zero as a Target:
- Missing Zero as a Target:
- Mistake: Not testing the algorithm with a target of zero.
- Solution: Explicitly test the algorithm with a target of zero to verify correctness.
- Overflow and Underflow:
- Ignoring integer overflow:
- Mistake: Not considering the possibility of integer overflow when calculating sums.
- Solution: Use data types that can handle large sums or implement checks to prevent overflow.
- Underestimating the Data Range:
- Mistake: Assuming the data range is within a certain limit.
- Solution: Be mindful of the potential range of data and choose appropriate data types.
- Handling negative numbers:
- Misinterpreting negative numbers:
- Mistake: Misinterpreting how negative numbers contribute to the target.
- Solution: Understand the impact of negative numbers on the target and adjust the algorithm accordingly.
Coding Best Practices:
- Modularity:
- Emphasizing the modular code:
- Break down the solution into modular functions or methods, each addressing a specific subtask.
- Encapsulate logic related to specific functionalities within dedicated functions.
- Advantages of modularity:
- Improved Readability: Each function focuses on a specific task, making the code easier to understand.
- Reusability: Modular functions can be reused in other parts of the code or in different projects.
- Easy Debugging: Isolate and troubleshoot issues in specific modules without affecting the entire codebase.
- Example (Python code):
def calculate_trapped_water(elevation_map):
# Function to calculate the amount of water trapped
# ...
def main():
# Main function to orchestrate the program
# ...
if __name__ == "__main__":
main()
- Variable Naming:
- The Importance of Meaningful Names:
- Choose descriptive and meaningful variable names that convey the purpose or content of the variable.
- Avoid single-letter variable names unless they represent common conventions (e.g., loop indices).
- Benefits of Good Variable Naming:
- Readability: Clear and descriptive names enhance code readability for yourself and others.
- Maintenance: Easier maintenance as the purpose of variables is evident.
- Reduced Comments: Well-named variables can reduce the need for excessive comments.
- Example (Python code):
def calculate_trapped_water(elevation_map):
# elevation_map: Input array representing the elevation map
# ...
for index, height in enumerate(elevation_map):
left_max = max(left_max, height)
# ...
- Consistent coding style:
- Maintain a consistent coding style throughout the codebase.
- Follow established conventions, such as PEP 8 for Python, for a uniform appearance.
- Version Control and Collaboration:
- Consistency facilitates version control and collaboration, especially in team environments.
- Adopting a consistent style ensures that team members can easily understand and contribute to the code.
- Example (Python code):
# Inconsistent Style
def calculateTrappedWater(elevationMap):
for i, n in enumerate(elevationMap):
rightMax = max(rightMax, n)
# ...
# Consistent Style (Following PEP 8)
def calculate_trapped_water(elevation_map):
for index, height in enumerate(elevation_map):
right_max = max(right_max, height)
# ...
Testing and Debugging:
Test cases:
- Test Case Selection:
- Test the solution with a variety of input scenarios to ensure its correctness.
- Include both typical cases and edge cases to cover a wide range of possibilities.
- Example Test Cases for "Trapping Rain Water":
- Positive cases with valid elevation maps that can trap water.
- Negative cases with no trapped water.
- Cases with an elevation map where no water can be trapped.
- Edge cases with empty elevation maps, single-element maps, and extreme elevation values.
- Test Case Execution:
- Automate the execution of test cases to streamline the testing process.
- Use testing frameworks or write custom test scripts to cover various scenarios.
Debugging techniques:
- Print Statements:
- Insert print statements strategically to output variable values and intermediate results.
- Helps identify where the code deviates from expected behavior.
- Use a debugger:
- Utilize integrated development environment (IDE) debuggers to set breakpoints and step through the code.
- Inspect variable values and control flow to pinpoint issues.
- Code Review:
- Engage in code reviews with peers or mentors.
- External perspectives can reveal overlooked errors or suggest alternative approaches.
- Rubber Duck Debugging:
- Explain the code step by step to an inanimate object (or a colleague).
- The act of verbalizing often helps in identifying logical errors.
- Isolated sections:
- Temporarily comment out or isolate specific sections of code to identify the source of errors.
- Narrow down the scope of investigation to smaller segments.
- Check variable values:
- Ensure that variables hold expected values at different stages of execution.
- Pay attention to changes in variable states.
- Use exception handling:
- Implement exception handling to catch and log errors.
- This prevents the program from crashing abruptly, providing information about the error.
- Reproduce the issue:
- Try reproducing the issue in a controlled environment.
- Identify the steps leading to the error and examine the relevant code.
- Logging:
- Incorporate logging statements to record the program's state during execution.
- Log messages provide insights into the program flow and variable values.
- Test incrementally:
- Implement and test the solution incrementally, focusing on small sections at a time.
- Detect issues early in the development process.
- Pair Programming:
- Collaborate with a partner in a pair programming session.
- Two sets of eyes can catch errors more effectively.
Algorithm Analysis:
Time and Space Complexity:
- Time Complexity Analysis:
- Evaluate the efficiency of the algorithm in terms of input size.
- Identify the dominant operations and quantify their relationship with input size.
- Example:
- For the Two Pointer Technique, the time complexity is O(n) since it involves iterating through the elevation map once.
- Space Complexity Analysis:
- Assess the algorithm's memory usage in relation to input size.
- Consider additional data structures and their impact on space complexity.
- Example:
- The Two Pointer Technique typically requires O(1) additional space since it operates in-place without extra data structures.
Trade-offs:
- Time vs. Space Complexity:
- Evaluate the trade-offs between optimizing for time or space.
- Some algorithms prioritize reduced time complexity, while others prioritize minimal space usage.
- Example Trade-off:
- The Two Pointer Technique offers improved time complexity (O(n)) but minimal space complexity (O(1)) compared to other approaches like the Stack-Based Approach.
- Memory efficiency vs. Speed:
- Consider the balance between memory efficiency and algorithmic speed.
- Optimize the algorithm based on the specific requirements and constraints of the problem.
- Example Trade-off:
- The Stack-Based Approach may offer better memory efficiency by utilizing a stack data structure but might sacrifice speed due to additional stack operations.
- Algorithmic Strategies:
- Choose algorithmic strategies based on the problem's characteristics and constraints.
- Select an approach that aligns with the specific goals of the application.
- Example Trade-off:
- The choice between the "Two Pointer" Technique and the Stack-Based Approach depends on factors such as available memory and the complexity of the elevation map.
- Scalability:
- Consider how well the algorithm scales as the input size increases.
- Choose an algorithm that maintains efficiency with growing datasets.
- Example Trade-off:
- The Two Pointer Technique may be more scalable for large elevation maps since its time complexity remains linear with input size, whereas other approaches may exhibit worse performance.
Application in Real-world Projects:
- Practical Use Cases:
- Urban Planning and Architecture:
- Scenario: Designing effective drainage systems or architectural features to manage rainwater in urban areas.
- Algorithmic Approach: Trapping Rain Water algorithms can assist in calculating the capacity needed for drainage systems or designing structures that can store rainwater effectively.
- Flood management:
- Scenario: Developing strategies to mitigate flooding in flood-prone regions or areas susceptible to heavy rainfall.
- Algorithmic Approach: Trapping Rain Water algorithms can provide insights into how much water certain areas can hold, helping in flood risk assessment and management planning.
- Environmental conservation:
- Scenario: Implementing eco-friendly solutions for rainwater harvesting and groundwater replenishment.
- Algorithmic Approach: By understanding how much rainwater can be trapped in various landscapes, conservationists can design sustainable water management systems that benefit ecosystems and communities.
- Agriculture and irrigation:
- Scenario: Optimizing irrigation practices to maximize water usage efficiency in agriculture.
- Algorithmic Approach: Trapping Rain Water algorithms can inform decisions about water distribution and storage on farms, reducing water waste and ensuring crops receive adequate moisture.
- Disaster Preparedness:
- Scenario: Planning for natural disasters such as hurricanes or typhoons that bring heavy rainfall.
- Algorithmic Approach: Trapping Rain Water algorithms can help emergency response teams estimate potential flood volumes and identify areas at risk, aiding in evacuation planning and resource allocation.
- Further exploration:
- Explore Additional Environmental Factors:
- Encourage learners to consider additional factors such as terrain slope, soil permeability, and vegetation cover, which can affect water retention and runoff.
- Algorithmic Variations:
- Explore variations of the Trapping Rain Water problem, such as considering irregular elevation maps or incorporating real-time rainfall data for dynamic water trapping calculations.
- Integration with Geographic Information Systems (GIS):
- Integrate Trapping Rain Water algorithms with GIS software to visualize water accumulation patterns on maps and assess their impact on urban development or natural ecosystems.
- Machine Learning Applications:
- Investigate machine learning approaches to predict rainfall patterns and optimize water management strategies based on historical data and environmental factors.
Example test cases:
Example test cases (Trapping Rain Water)
- Positive cases with valid elevation maps:
- Input: heights = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
Expected output: 6 - Negative cases with no trapped water:
- Input: heights = [3, 1, 2, 4, 5]
Expected output: 0 (no water trapped as each bar's height is greater than or equal to adjacent bars) - Edge cases with empty arrays, single-element arrays, and extreme values:
- Input: heights = []
Expected output: 0 (empty array) - Input: heights = [5]
Expected output: 0 (single-element array) - Input: heights = [0, 1000000000, 0, 1000000000, 0]
Expected output: 0 (no water trapped as each bar's height is greater than or equal to adjacent bars)
Solution for different languages:
Python - Trapping Rain Water
Code:
# Function to calculate the amount of trapped rainwater given an elevation map
def trap(height):
# Get the length of the height array
n = len(height)
# If the array is empty, return 0 as no water can be trapped
if n == 0:
return 0
# Initialize arrays to store the maximum height of bars to the left and right of each bar
left_max = [0] * n
right_max = [0] * n
# Compute the maximum height of bars to the left of each bar
left_max[0] = height[0]
for i in range(1, n):
left_max[i] = max(left_max[i - 1], height[i])
# Compute the maximum height of bars to the right of each bar
right_max[n - 1] = height[n - 1]
for i in range(n - 2, -1, -1):
right_max[i] = max(right_max[i + 1], height[i])
# Calculate the amount of water trapped by each bar
water_trapped = 0
for i in range(n):
water_trapped += min(left_max[i], right_max[i]) - height[i]
# Return the total amount of trapped water
return water_trapped
# Test cases
print(trap([0,1,0,2,1,0,1,3,2,1,2,1])) # Output: 6
print(trap([3,1,2,4,5])) # Output: 3
print(trap([])) # Output: 0
print(trap([5])) # Output: 0
print(trap([0, 1000000000, 0, 1000000000, 0])) # Output: 1000000000
Output:
6 3 0 0 1000000000
Explanation of the said Python code:
- Function definition (trap(height)):
- This function takes an array 'height' as input, representing the heights of bars in an elevation map.
- Initialization:
- It initializes variables 'n' to store the length of the 'height' array.
- If the 'height' array is empty (n == 0), it returns 0 as there's no water trapped.
- Compute Left and Right Max Heights:
- Two arrays, 'left_max' and 'right_max', are initialized to store the maximum height of bars to the left and right of each bar, respectively.
- The 'left_max' array is computed by iterating through the 'height' array from left to right, storing the maximum height encountered so far.
- The 'right_max' array is computed by iterating through the 'height' array from right to left, storing the maximum height encountered so far.
- Calculate trapped water:
- The amount of water trapped at each bar is calculated by taking the minimum of the maximum heights to the left and right of the bar and subtracting the height of the bar itself.
- This calculation is performed for each bar, and the total amount of trapped water is accumulated.
- Return Total Trapped Water:
- The total amount of trapped water is returned as the result of the function.
Java - Trapping Rain Water
Code:
public class Solution { // Define the Solution class
public int trap(int[] height) { // Define the trap method taking an array of integers
int n = height.length; // Get the length of the input array
if (n == 0) return 0; // If the array is empty, return 0
int[] leftMax = new int[n]; // Create an array to store the left maximum heights
int[] rightMax = new int[n]; // Create an array to store the right maximum heights
leftMax[0] = height[0]; // Initialize the left maximum with the first height
for (int i = 1; i < n; i++) { // Loop through the array
leftMax[i] = Math.max(leftMax[i - 1], height[i]); // Calculate the left maximum for each position
}
rightMax[n - 1] = height[n - 1]; // Initialize the right maximum with the last height
for (int i = n - 2; i >= 0; i--) { // Loop through the array in reverse
rightMax[i] = Math.max(rightMax[i + 1], height[i]); // Calculate the right maximum for each position
}
int waterTrapped = 0; // Initialize the variable to store the trapped water
for (int i = 0; i < n; i++) { // Loop through the array
waterTrapped += Math.min(leftMax[i], rightMax[i]) - height[i]; // Calculate the trapped water at each position
}
return waterTrapped; // Return the total trapped water
}
public static void main(String[] args) { // Main method
Solution solution = new Solution(); // Create an instance of the Solution class
System.out.println(solution.trap(new int[]{0,1,0,2,1,0,1,3,2,1,2,1})); // Output: 6
System.out.println(solution.trap(new int[]{3,1,2,4,5})); // Output: 0
System.out.println(solution.trap(new int[]{})); // Output: 0
System.out.println(solution.trap(new int[]{5})); // Output: 0
System.out.println(solution.trap(new int[]{0, 1000000000, 0, 1000000000, 0})); // Output: 0
}
}
Output:
6 3 0 0 1000000000
Explanation of the said Java code:
- trap Method:
- This method takes an array of integers 'height' as input and returns an integer representing the total amount of water trapped after raining.
- It first checks if the length of the 'height' array is 0. If it is, it returns 0, indicating that there is no water trapped.
- Two arrays, 'leftMax' and 'rightMax', are initialized to store the maximum height of bars to the left and right of each bar, respectively.
- Compute Left and Right Max Heights:
- The 'leftMax' array is computed by iterating through the 'height' array from left to right, storing the maximum height encountered so far.
- The 'rightMax' array is computed by iterating through the 'height' array from right to left, storing the maximum height encountered so far.
- Calculate Trapped Water:
- The amount of water trapped at each bar is calculated by taking the minimum of the maximum heights to the left and right of the bar and subtracting the height of the bar itself.
- This calculation is performed for each bar, and the total amount of trapped water is accumulated.
- Return Total Trapped Water:
- The total amount of trapped water is returned as the result of the trap method.
- main Method:
- This method serves as the entry point of the program.
- It creates an instance of the "Solution" class and calls the "trap()" method with various test cases.
- The results of the trap method for each test case are printed to the console.
C++ - Trapping Rain Water
Code:
#include <iostream> // Include the input-output stream library
#include <vector> // Include the vector container library
#include <algorithm> // Include the algorithm library for min and max functions
using namespace std; // Use the standard namespace
class Solution { // Define the Solution class
public:
int trap(vector<int>& height) { // Define the trap method taking a vector of integers by reference
int n = height.size(); // Get the size of the input vector
if (n == 0) return 0; // If the vector is empty, return 0
vector<int> leftMax(n); // Create a vector to store the left maximum heights
vector<int> rightMax(n); // Create a vector to store the right maximum heights
leftMax[0] = height[0]; // Initialize the left maximum with the first height
for (int i = 1; i < n; i++) { // Loop through the vector
leftMax[i] = max(leftMax[i - 1], height[i]); // Calculate the left maximum for each position
}
rightMax[n - 1] = height[n - 1]; // Initialize the right maximum with the last height
for (int i = n - 2; i >= 0; i--) { // Loop through the vector in reverse
rightMax[i] = max(rightMax[i + 1], height[i]); // Calculate the right maximum for each position
}
int waterTrapped = 0; // Initialize the variable to store the trapped water
for (int i = 0; i < n; i++) { // Loop through the vector
waterTrapped += min(leftMax[i], rightMax[i]) - height[i]; // Calculate the trapped water at each position
}
return waterTrapped; // Return the total trapped water
}
};
int main() { // Main function
Solution solution; // Create an instance of the Solution class
vector<int> heights1 = {0,1,0,2,1,0,1,3,2,1,2,1}; // Define test case heights1
vector<int> heights2 = {3,1,2,4,5}; // Define test case heights2
vector<int> heights3 = {}; // Define test case heights3 as an empty vector
vector<int> heights4 = {5}; // Define test case heights4 with a single height
vector<int> heights5 = {0, 1000000000, 0, 1000000000, 0}; // Define test case heights5
cout << solution.trap(heights1) << endl;
cout << solution.trap(heights2) << endl;
cout << solution.trap(heights3) << endl;
cout << solution.trap(heights4) << endl;
cout << solution.trap(heights5) << endl;
return 0; // Return 0 to indicate successful execution
}
Output:
6 3 0 0 1000000000
Explanation of the said C++ code:
- The code begins by including the necessary libraries: iostream for input-output operations, vector for dynamic arrays, and algorithm for functions like min and max.
- The "Solution" class is defined, containing the "trap()" method. This method takes a vector of integers ('height') by reference and returns an integer representing the total amount of trapped water.
- Inside the trap method:
- It first calculates the size of the input vector 'height' and checks if it's empty. If empty, it returns 0.
- Two vectors, 'leftMax' and 'rightMax', are created to store the left and right maximum heights encountered so far, respectively.
- The 'leftMax' vector is filled by iterating through the input vector from left to right, storing the maximum height encountered at each position.
- The 'rightMax' vector is filled by iterating through the input vector from right to left, storing the maximum height encountered at each position.
- Finally, it calculates the trapped water at each position by taking the minimum of 'leftMax' and 'rightMax' for that position and subtracting the height of the current bar. The total trapped water is accumulated in the variable 'waterTrapped'.
- In the main function:
- An instance of the "Solution" class is created.
- Test cases represented by vectors 'heights1' to 'heights5' are defined.
- The "trap()" method is called for each test case, and the result is printed to the console using "cout".
- The program ends by returning 0, indicating successful execution.
C# - Trapping Rain Water
Code:
using System; // Include the System namespace for basic functionalities
public class Solution // Define the Solution class
{
public int Trap(int[] height) // Define the Trap method taking an array of integers as input
{
int n = height.Length; // Get the length of the input array
if (n == 0) return 0; // If the array is empty, return 0
int[] leftMax = new int[n]; // Create an array to store the left maximum heights
int[] rightMax = new int[n]; // Create an array to store the right maximum heights
leftMax[0] = height[0]; // Initialize the left maximum with the first height
for (int i = 1; i < n; i++) // Loop through the array
{
leftMax[i] = Math.Max(leftMax[i - 1], height[i]); // Calculate the left maximum for each position
}
rightMax[n - 1] = height[n - 1]; // Initialize the right maximum with the last height
for (int i = n - 2; i >= 0; i--) // Loop through the array in reverse
{
rightMax[i] = Math.Max(rightMax[i + 1], height[i]); // Calculate the right maximum for each position
}
int waterTrapped = 0; // Initialize the variable to store the trapped water
for (int i = 0; i < n; i++) // Loop through the array
{
waterTrapped += Math.Min(leftMax[i], rightMax[i]) - height[i]; // Calculate the trapped water at each position
}
return waterTrapped; // Return the total trapped water
}
static void Main(string[] args) // Main method
{
Solution solution = new Solution(); // Create an instance of the Solution class
Console.WriteLine(solution.Trap(new int[] { 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 })); // Output: 6
Console.WriteLine(solution.Trap(new int[] { 3, 1, 2, 4, 5 })); // Output: 0
Console.WriteLine(solution.Trap(new int[] { })); // Output: 0
Console.WriteLine(solution.Trap(new int[] { 5 })); // Output: 0
Console.WriteLine(solution.Trap(new int[] { 0, 1000000000, 0, 1000000000, 0 })); // Output: 0
}
}
Output:
6 3 0 0 1000000000
Explanation of the said C# code:
- Using Directives: The code includes necessary using directives for basic functionalities like input-output operations and mathematical functions.
- Solution Class: Defines a class named "Solution".
- Trap Method:
- The "Trap()" method takes an integer array 'height' as input and returns the total trapped water as an integer.
- It first calculates the length of the input array 'n'.
- If n is 0 (indicating an empty array), it returns 0.
- It initializes two arrays 'leftMax' and 'rightMax' to store the left and right maximum heights respectively.
- It calculates the left maximum heights for each position in the 'height' array and stores them in the 'leftMax' array using a loop.
- Similarly, it calculates the right maximum heights for each position in the 'height' array and stores them in the 'rightMax' array using a loop.
- It then iterates through each position in the 'height' array and calculates the trapped water at that position by subtracting the current height from the minimum of the corresponding left and right maximum heights.
- The calculated trapped water is accumulated in the variable waterTrapped.
- Main Method:
- The "Main()" method serves as the entry point of the program.
- It creates an instance of the "Solution" class.
- It calls the "Trap()" method for five different test cases and prints the result of each test case using "Console.WriteLine".
JavaScript - Trapping Rain Water
Code:
function trap(height) { // Define the trap function taking an array of heights as input
const n = height.length; // Get the length of the input array
if (n === 0) return 0; // If the array is empty, return 0
const leftMax = new Array(n).fill(0); // Create an array to store left maximum heights, initialized with 0
const rightMax = new Array(n).fill(0); // Create an array to store right maximum heights, initialized with 0
leftMax[0] = height[0]; // Initialize the first element of leftMax with the first height
for (let i = 1; i < n; i++) { // Iterate through the array starting from index 1
leftMax[i] = Math.max(leftMax[i - 1], height[i]); // Calculate the left maximum height for each position
}
rightMax[n - 1] = height[n - 1]; // Initialize the last element of rightMax with the last height
for (let i = n - 2; i >= 0; i--) { // Iterate through the array in reverse starting from the second last element
rightMax[i] = Math.max(rightMax[i + 1], height[i]); // Calculate the right maximum height for each position
}
let waterTrapped = 0; // Initialize a variable to store the trapped water
for (let i = 0; i < n; i++) { // Iterate through the array
waterTrapped += Math.min(leftMax[i], rightMax[i]) - height[i]; // Calculate the trapped water at each position
}
return waterTrapped; // Return the total trapped water
}
// Test cases
console.log(trap([0,1,0,2,1,0,1,3,2,1,2,1])); // Output: 6
console.log(trap([3,1,2,4,5])); // Output: 0
console.log(trap([])); // Output: 0
console.log(trap([5])); // Output: 0
console.log(trap([0, 1000000000, 0, 1000000000, 0])); // Output: 0
Output:
6 3 0 0 1000000000
Explanation of the said JavaScript code:
- Function Definition (trap):
- The "trap()" function takes an array 'height' as input.
- It calculates the amount of water that can be trapped after raining based on the elevation map represented by the input array.
- Initialization:
- It initializes variables 'n' to store the length of the input array.
- If the length 'n' is zero, indicating an empty array, it returns 0 as there is no water trapped.
- Left and Right Maximum Heights:
- It initializes arrays 'leftMax' and 'rightMax' to store the left and right maximum heights, respectively, for each position in the input array.
- The 'leftMax' array is filled with zeros initially.
- It iterates through the input array from left to right, updating 'leftMax' to store the maximum height encountered so far at each position.
- Similarly, it iterates through the input array from right to left, updating 'rightMax' to store the maximum height encountered so far at each position.
- Trapped Water Calculation:
- It initializes a variable 'waterTrapped' to store the total trapped water.
- It iterates through the input array, calculating the trapped water at each position based on the minimum of the left and right maximum heights minus the height of the current position.
- It adds the calculated trapped water to the 'waterTrapped' variable.
- Return:
- It returns the total trapped water calculated.
Time and Space Complexity:
- Time Complexity:
- The code consists of three main loops:
- The first loop iterates over the height array to calculate the maximum height of bars to the left of each bar ('left_max'). This loop runs in O(n) time, where n is the length of the height array.
- The second loop iterates over the height array in reverse to calculate the maximum height of bars to the right of each bar ('right_max'). This loop also runs in O(n) time.
- The third loop iterates over the height array to calculate the amount of water trapped by each bar and accumulate the total trapped water. This loop runs in O(n) time.
- Therefore, the overall time complexity of the code is O(n), where n is the length of the height array.
- Space Complexity:
- The code utilizes additional space to store two arrays ('left_max' and 'right_max') of size n, where n is the length of the height array. Hence, the space complexity of the code is O(n).
- Apart from these arrays, the code uses a few extra variables ('n', 'water_trapped', and loop counters), which occupy constant space and do not affect space complexity.
- Therefore, the overall space complexity of the code is O(n).
It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.
https://w3resource.com/data-structures-and-algorithms/array/dsa-trapping-rain-water.php
- Weekly Trends and Language Statistics
- Weekly Trends and Language Statistics