接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
- 输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
- 输出:6
- 解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
- 输入:height = [4,2,0,3,2,5]
- 输出:9
接雨水的变形题——华为机考的管道漏水题
在上题的基础上,在地下凿洞,把水全部漏掉。水从它的地势最低处漏掉。每个水洼只能凿一个洞。该洞位于最底处的最左边。如果水可以从左右两个坑漏掉,则漏到左右中最深的坑里面,如果两个坑一样深,就漏到左边。
如下图所示:
输入为:
0 1 0 2 1 0 1 3 2 1 2 1
结果为:
2 1
5 4
9 1
思路
计算每个单位的蓄水,然后判断该单位要从哪个位置漏掉。
最后合并单个水洼里面因为底部平坦而有的多个洞口位置,全部合并到底部左边的位置。
我的题解
package HuaWei;
import java.util.*;
public class LeakWater {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String[] s=sc.nextLine().split("\\s+");
int[] height=new int[s.length];
for(int i=0;i<s.length;i++){
height[i]=Integer.parseInt(s[i]);
}
// 1. find water remains per step
int[] leftMax=new int[s.length];
int[] rightMax=new int[s.length];
leftMax[0]=height[0];
for(int i=1;i<leftMax.length;i++){
leftMax[i]=Math.max(leftMax[i-1],height[i]);
}
rightMax[rightMax.length-1]=height[height.length-1];
for(int i=rightMax.length-2;i>=0;i--){
rightMax[i]=Math.max(rightMax[i+1],height[i]);
}
int[] water=new int[s.length];
for(int i=1;i<water.length-1;i++){
int top=Math.min(leftMax[i],rightMax[i]);
int bottom=height[i];
water[i]=top-bottom;
}
System.out.println("water");
for(int i=0;i<water.length;i++){
System.out.println(water[i]);
}
System.out.println("end water");
// 2. find where to leak per step
// 2.1 find the left leak point and right leak point
int[] leftMin=new int[s.length];
int[] rightMin=new int[s.length];
boolean isDown=false;
int pre=height[s.length-1];
int down=s.length-1;
for(int i=s.length-2;i>=1;i--){
if(pre>height[i]){
isDown=true;
}else if(pre<height[i]){
isDown=false;
}
if(!isDown){
rightMin[i]=down;
}else{
down=i;
rightMin[i]=down;
}
pre=height[i];
}
pre=height[0];
down=0;
for(int i=1;i<s.length-1;i++){
if(pre>height[i]){
isDown=true;
}else if(pre<height[i]){
isDown=false;
}
if(!isDown){
leftMin[i]=down;
}else{
down=i;
leftMin[i]=down;
}
pre=height[i];
}
// 2.2 leak water to its lowest position by comparing the left and right leak point's depth
int[] result=new int[s.length];
for(int i=0;i<water.length;i++){
int destination=0;
int leftV=height[leftMin[i]];
int rightV=height[rightMin[i]];
if(leftV<=rightV){
destination=leftMin[i];
}else{
destination=rightMin[i];
}
result[destination]+=water[i];
}
// 2.3 union the leak positions that have the same depth
int parents=0;
int i=0;
while(i<s.length){
if(result[i]!=0){
parents=i;
i++;
while(i<s.length&&result[i]!=0&&height[parents]==height[i]){
result[parents]+=result[i];
result[i]=0;
i++;
}
} else{
i++;
}
}
// output the result
for(int j=0;j<s.length;j++){
if(result[j]!=0){
System.out.println(j+" "+result[j]);
}
}
}
}