給定 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
每次找出最高的柱子和第二高的柱子,得出它們之間能容納的雨水,然後通過遞歸得到左半部和右半部的結果相加就是所有的雨水了。
class Solution {
public int trap(int[] height) {
if(height==null || height.length == 0 || height.length == 1){
return 0;
}
int start = 0;
int end = height.length - 1;
//去掉開頭的0
while(height[start] == 0){
start++;
}
//去掉末尾的0
while(height[end] == 0){
end --;
}
if(start +1 >= end){
return 0;
}
return recursion(arraySub(height,start,end));
}
public int recursion(int[] res){
int total = 0;
int start = 0;
int end = res.length - 1;
for(int i = 1; i<res.length -1;i++){
//得到res中最高的兩個柱子的座標
if(res[i] > res[start] || res[i] > res[end]){
if(res[start] > res[end]){
end = i;
}else{
start = i;
}
}
}
//有可能出現end<start的情況
if(start > end){
int tmp = start;
start = end;
end = tmp;
}
//考慮兩個柱子相鄰的情況,就沒必要計算了
if(start + 1 != end){
//取兩個柱子中較矮的那根
if(res[start] > res[end]){
total = res[end] * (end - start - 1);
}else{
total = res[start] * (end - start - 1);
}
//減去兩根柱子之間的那些柱子的高度就是結果
for(int i = start + 1;i < end;i++){
total -= res[i];
}
}
//在start=1的情況下左子集必然只有兩根柱子,所以不用考慮
if(start > 1){
//求左子集的雨水
total += recursion(arraySub(res,0,start));
}
if(end < res.length-2){
//求右子集的雨水
int[] newRes = new int[res.length - end];
System.arraycopy(res,end,newRes,0,newRes.length);
total += recursion(newRes);
}
return total;
}
public static int[] arraySub(int[] data,int start,int end){
int[] C=new int[end-start+1];//新建數組C長度爲start-end
for(int i=start,j=0;i<=end;i++,j++){
C[j]=data[i];
}
return C;//返回截取數組的地址
}
}