面试算法题-接雨水
题目:
给定 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
提示:
n == height.length
0 <= n <= 3 * 104
0 <= height[i] <= 105
接雨水问题应该是面试中较为经典且有难度的题目,面对这种题目,一般的方法就是先记住解题方法,再尝试理解
思路:
1、不要尝试去计算区域可容水量,只算每个刻度上面的水量,最后将每个刻度上的水量相加即可容水量会更加直观
2、如果需要算出每个刻度上可容水量,需要算出此刻度左右两边最高位置最后求 min(max(left),max(right)),因为可容水量取决于小的那个
3、使用 left、right 双指针来算出每个刻度左边和右边最高位置,避免每个刻度都对左右进行一次扫描,增加时间复杂度
代码:
/**
* 双指针方法
* left,right 两边,哪边的 max 小,先算哪边的水量
* @param arr
* @return
*/
public static int trap(int[] arr){
if(arr == null || arr.length <2){
return 0;
}
int N = arr.length;
int L = 1;
int leftMax = arr[0];
int R = N - 2;
int rightMax = arr[N - 1];
int water = 0;
// 当左右部分相碰,所有的的水量结算结束
while(L <= R){
if (leftMax <= rightMax){
water += Math.max(0,leftMax - arr[L]);
leftMax = Math.max(leftMax,arr[L++]);
}else {
water += Math.max(0,rightMax - arr[R]);
rightMax = Math.max(rightMax,arr[R--]);
}
}
return water;
}