(violence + pruning) leetcode difficulty 42. Catch the rain

topic

Given n non-negative integers representing the height map of each column with a width of 1, calculate how much rain the column can receive after it rains.

Sample

Example 1:

insert image description here

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Explanation: The above is composed of the array [0,1,0,2,1,0 ,1,3,2,1,2,1] represents the heightmap, in this case, you can pick up 6 units of rain (the blue part represents rain).

Example 2:
Input: height = [4,2,0,3,2,5]
Output: 9

提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105

Source: LeetCode
Link: https://leetcode-cn.com/problems/trapping-rain-water The
copyright belongs to LeetCode.com. For commercial reprints, please contact the official authorization, and for non-commercial reprints, please indicate the source.

analyze

It is easy to read and understand the meaning of the question according to the picture. First of all, let's think about how to judge the maximum amount of rainwater it can receive on a grid. For example, the grid in the middle of 2 0 2 can receive 2, and the grid in the middle of 2 0 100 can also receive 2. , it can be said to be the barrel effect, 3 2 0 100, the grid of 0 can be connected to 3, so how much water a grid can receive depends on the columns on its left and right, we need to find the highest column on the left and the highest column on the right respectively , and then find the smaller of the two columns and subtract the height of the column on our current grid, which is the maximum amount of water that can be received.
The simple teacher who listened to the Nine Chapters Algorithms talk about bfs before. He said that if you don’t think of a better solution at the beginning, violence is the best way. Anyway, it won’t take much time to write a violent solution, so we just use violence. The method then analyzes how to optimize (pruning or memoized search, etc.)

Find the largest on the left and the largest on the right each time, and then take the smaller one and subtract the height of the current grid (the smaller one must be greater than the height of the current grid, otherwise the current grid cannot receive water)

To analyze how to optimize, our outer loop is each grid, which is n, and the inner loop also traverses the entire array each time, so the total time complexity is O(n^2), then consider what the repeated steps are, the outer loop does not The method is simplified, because each grid must be traversed, and the inner loop can be simplified to find the largest left and largest right each time.

Simplify the maximum on the left, we traverse from left to right, each grid is the left side of the next grid, so we only need to compare the size of the current grid and the maximum value on the left, if the current grid is larger, then we next grid on the left The largest grid is the current grid

Simplify the largest on the right. We can see from the figure that we only need to update the largest grid on the right until the grid height is 3, so here we first loop once to find the current largest on the right and the time of the next update We only update when we reach the maximum grid we set.

code section

initialization

First initialize an array to store the maximum amount of rainwater that can be stored in each grid, then initialize the variables representing the maximum column heights on the left and right, initialize the height of the first element on the left, and then compare each time loop, if the current If the height of the column is greater than it, it will be updated for the next grid, and the maximum value on the right is -1, because it is impossible for the height of the column to be -1. In special cases, we have to loop once to find the maximum value on the right for the first time. , and then we update it only when we reach the column with the set maximum value.

		int len=height.size();
		vector<int> f(len,0);
		int lm=height[0],rm=-1;
core part

update right max

			int j=i+1;
		
			if(rm<0||height[i]==rm)		//如果当前到达最大值,更新 
			{
    
    
				rm=0;
				while(j<len)
				{
    
    
					if(height[j]>rm)
						rm=height[j];
					++j;
				}
			}

Determine the amount of rainwater that the current grid can catch. The current column is smaller than the largest column on the left and right to catch the rainwater.

			if(lm>height[i]&&rm>height[i])
			{
    
    
				f[i]=min(lm,rm)-height[i];
			}

For the next column, update the left largest

			
			if(height[i]>lm)		//当前值比左边最大值要大,更新下一个的lm 
				lm=height[i];

full code

class Solution {
    
    
public:
    int trap(vector<int>& height) {
    
    
		int len=height.size();
		vector<int> f(len,0);
		int lm=height[0],rm=-1;		
		
		for(int i=1;i<len-1;i++)
		{
    
    
			int j=i+1;
		
			if(rm<0||height[i]==rm)		//如果当前到达最大值,更新 
			{
    
    
				rm=0;
				while(j<len)
				{
    
    
					if(height[j]>rm)
						rm=height[j];
					++j;
				}
			}
			
			if(lm>height[i]&&rm>height[i])
			{
    
    
				f[i]=min(lm,rm)-height[i];
			}
			
			if(height[i]>lm)		//当前值比左边最大值要大,更新下一个的lm 
				lm=height[i];
			
		}
		
		long long sum=0;
		for(int i=1;i<len-1;i++)
			sum+=f[i];
			
		return sum;
    }
};

Summarize

After reading a question, if you can only think of a violent method at the beginning, write it, judge the repeated situation after writing, and then perform pruning, memory search, etc.
This question is the most perfect method I have seen so far. Using dynamic programming, two state arrays are opened up, representing the largest left and largest right on each grid, and then almost the same idea as my pruning is used to judge each grid. The time complexity is visually O(n), and the amount of code is much less than what I wrote.

Guess you like

Origin blog.csdn.net/weixin_46035615/article/details/123818481