This is the 9th day of my participation in the August More Text Challenge. For details, see:August is more challenging
preface
Force button 42 catch rain as follows:
Given n non-negative integers representing the height diagram of each column of width 1, calculate how much rain can be received by the columns arranged in this order after it rains.
Example 1:
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1] output: 6Copy the code
Example 2:
Input: height = [4,2,0,3,2,5Copy the code
A, thinking
In fact, I just started to think: if you need to catch rain there must be a peak and valley, that is, first decrease and then increase. So finding all the peaks and valleys and peaks will give you an accurate calculation of the area.
The implementation code looks like this (error demonstration) :
public int trap(int[] height) {
if (height == null || height.length<3)
return 0;
int ret = 0;
int len = height.length;
// Only when there are valleys can the rain be contained
boolean down = false;
int left = 0;
List<Integer> boundary = new ArrayList<>();
// Find all the valleys from left to right
for (int i=1; i<len; i++) {
if (height[i] >= height[i-1]) {
left = i ;
down = false;
} else {
if(! down) {// The trend is downward
down = true;
boundary.add(left);
// If there are two elements
if (boundary.size() == 2) {
// Calculate the height
ret += calc(height, boundary.get(0), boundary.get(1));
boundary.clear();
down = false; }}}}return ret;
}
public int calc(int[] height, int a, int b) {
int ret = 0;
int min = Math.min(height[a], height[b]);
for (int i=a; i<=b; i++) {
ret += Math.max(min - height[i], 0);
}
return ret;
}
Copy the code
But I find it impossible to deal with situations where the peak to the left of a particular peak or valley is not immediately adjacent to the current peak or valley
So the key to solving this problem is to find the highest point to the left and the highest point to the right of each subscript I
The overall step is divided into two steps:
- Find all the subscripts
i
The correspondingLeft a peak
和The highest point right
- The traversal computes the area and: subscript
i
The corresponding area is zeroLower high minus current height (similar to barrel effect, depending on short board)
, the formula forMath.min(leftMax[i], rightMax[i]) - height[i]
The process of finding the highest point can be seen in the following example
For example (find the highest point)
Parameter Description leftMax[] : indicates the left highest point array
Here to find the left highest point as an example, the right highest point step is the same, so omit
= math.max (leftMax[i-1], height[I])
So all we need to do is walk through the array from left to right, and we can initialize the left highest point array
Tips: The above process is simple dynamic programming (using the state transition equation, solved from the bottom up)
Second, the implementation
The implementation code
The implementation code is consistent with the idea
public int trap(int[] height) {
if (height == null || height.length<3)
return 0;
int ret = 0;
int len = height.length;
int[] leftMax = new int[len]; // I subscript and its highest left element
int[] rightMax = new int[len]; // The highest element to the right of the I index
// Initialize leftMax
leftMax[0] = height[0];
for (int i=1; i<len; i++) {
leftMax[i] = Math.max(leftMax[i-1], height[i]);
}
// Initialize rightMax
rightMax[len -1] = height[len - 1];
for (int i=len-2; i>-1; i--) {
rightMax[i] = Math.max(rightMax[i+1], height[i]);
}
// Calculate the area
for (int i=0; i<len; i++) {
ret += Math.min(leftMax[i], rightMax[i]) - height[i];
}
return ret;
}
Copy the code
The test code
public static void main(String[] args) {
int[] nums = {4.2.0.3.2.5};
new Number42().trap(nums);
}
Copy the code
The results of
Third, summary
Thank you for seeing the end, it is my great honor to help you ~♥