42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
思路:
从左边一侧使用双指针,i 记录低柱子 ,而 j 记录比 i 高或者相等的柱子,若找不到比 i 要大或者相等的柱子,那也要围起来接水对吧,所以就取 j 在遍历过程中的最大柱子 (用maxp来记录) 每次围成了接水坑之后,i 指针就从 j 或者maxp这个地方开始下一次的遍历 ,继续找可以围起来接水的,emmmm,大概就这样,通俗易懂,但并不是最优方法,望有所帮助
import java.util.Scanner;
public class 接雨水 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] a = new int[n];
for(int i=0;i<n;i++)
{
a[i] = in.nextInt();
}
System.out.println(trap(a));
}
public static int trap(int[] height) {
if(height.length<=1)
return 0;
int n = height.length;
int sum = 0;
for(int i=0;i<n-1;i++)
{
//System.out.println("这是i: "+i+" heaight[i]: "+height[i]);
int maxp = i+1;
boolean flag = false;
for(int j=i+1;j<n;j++)
{
if(height[j]>=height[maxp])
maxp = j;
if(height[j] >= height[i])
{
int minheight =Math.min(height[i], height[j]);
sum += (j-i-1)*minheight-blockArea(height,i,j,minheight);
i=j-1;//因为for的最后还要i++ 所以不是i=j 细节
flag = true;
break;
}
}
if(!flag)
{
int minheight =Math.min(height[i], height[maxp]);
sum += (maxp-i-1)*minheight-blockArea(height,i,maxp,minheight);
i=maxp-1;
}
}
return sum;
}
private static int blockArea(int[] a,int x, int y, int max) {
int area =0;
for(int i=x+1;i<y;i++)
{
area += Math.min(max, a[i]);
}
return area;
}
}