给定一个数组代表一个容器, 比如[3,1,2,4],
代表0位置是一个宽度为1,高度为3的直方图。
代表1位置是一个宽度为1,高度为1的直方图。
代表2位置是一个宽度为1,高度为2的直方图。
代表3位置是一个宽度为1,高度为4的直方图。
所有直方图的底部都在一条水平线上,且紧靠着。
把这个图想象成一个容器,这个容器可以装3格的水。
给定一个没有负数的数组arr,返回能装几格水?
分析,每个位置可以盛水的原理。
他们可以乘的水。就是左边最高的墙和右边最高的墙中 比较低的那个。 减去自己的高度
如果减后为负值。说明一点水都乘不了。↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
分析的是每个位置可以盛的水
需要的数据是。每个位置。左边所有数组的最大值。右边所有数组的最大值。
使用预处理数组,保存结果
减少时间复杂度。计算总乘水量 时间复杂度O(N)
public static int getWater1(int[] arr){
if (arr == null || arr.length < 3) {
return 0;
}
int len = arr.length;
//意义: 0 位置左边所有值中最大的。 1位值左边所有值中最大的。..
int[] L = new int[len];
//意义: 0 位置右边所有值中最大的。 1位值右边所有值中最大的。...
int[] R = new int[len];
L[0] = arr[0];
for(int i=1;i<len;i++){
L[i] = Math.max(arr[i],R[i-1]);
}
R[len-1] = arr[len-1];
for(int i=len-2;i>=0;i--){
R[i] = Math.max(R[i+1],arr[i]);
}
System.out.println(Arrays.toString(L));
System.out.println(Arrays.toString(R));
//利用原理和,需求数据求值
//最前和最后不可能盛水
int res = 0;
for(int i=1;i<len-1;i++){
//计算最短的墙。减去自己的高度
int min = Math.min(L[i-1],R[i+1])-arr[i];
res += min<0?0:min;
}
return res;
}
分析预处理数组的值变化情况。和题意
最优解:
public static int getWater2(int[] arr){
if (arr == null || arr.length < 3) {
return 0;
}
int res = 0;
for(int l=0,r=arr.length-1;l+1<=r-1;){
if(arr[l]<arr[r]){
res += Math.max(0,arr[l]-arr[l+1]);//防止盛水量出现负数
l++;
}else if(arr[l]>arr[r]){
res += Math.max(0,arr[r]-arr[r-1]);
r--;
}else{//墙高度相等,l和r谁变化都无所谓
res += Math.max(0,arr[r]-arr[r-1]);
r--;
}
}
return res;
}