题目描述:
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
如图:
解析:
其实这个替换换一个名称,就比较流行了“接雨水”,这是力扣上面的42题。力扣的测试用例更加有普遍性。
青豆可以在像容器的柱子之间进行存放,可以看作两边高中间低。存放数量通过高度差进行计算,可以考虑到最高位置处索引为max,这里不可能有青豆。下面主要看我的trap方法。
方法:动态规划
- l[i]为从左往右到i扫描所能存放青豆数的和,l也就是前缀和
- r[i]为从右往左到i扫描所能存放青豆数的和,r也就是后缀和
- lm为,从左往右扫描中for循环中,左边最大值
- rm为,从右往左扫描中for循环中,右边最大值
- max为,数组中最大值的索引
从左往右,开始记录左边最大为lm=height[0]和max=0,假设右边有一个最高值使得能够和lm形成两大夹一小的容器装青豆,然后和后面对比,如果lm>height[i],那么青豆数量就lm-height[i],否则就是更新lm还有max。只有在到达height中最大值的时候这个算法都会成立,因为假设不成立。
从右往左,同上。
从左往右或者从右往左统计对于任意下标为i的柱子,在到达最高的柱子height[max]时候都是正确的。l[i]统计的是在从左往右的i位置能装的所有青豆,r[i]统计的是从右往左到i位置所能装的青豆数,最后通过l和r记录的数据进行做差得到ans。
/**
* 支持 import Java 标准库 (JDK 1.8)
*/
import java.util.*;
/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
public static void main(String []args) {
int[] nums = {5, 0, 2, 1, 4, 0, 1, 0, 3};
int res=trap(nums);
System.out.println(res);
}
public static int trap(int[] height) {
int[] l=new int[height.length];
int[] r=new int[height.length];
int lm=height[0];
int rm=height[height.length-1];
int max=0;
for(int i=1;i<height.length;i++){
if(lm>height[i]){
l[i]=l[i-1]+lm-height[i];
}else{
l[i]=l[i-1];
lm=height[i];
max=i;
}
}
for(int i=height.length-2;i>=0;i--){
if(rm>height[i]){
r[i]=r[i+1]+rm-height[i];
}else{
r[i]=r[i+1];
rm=height[i];
}
}
int ans=0;
ans+=l[max];
ans+=r[max];
return ans;
}
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n)