当青训营遇见码上掘金。 接青豆,其实是接雨水。经典中的经典
主题 4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
这里写了一个简单做法,直接双向遍历各一次,用来获取左右两边的最大值,获取这两个最大值中的较小的一个。就是雨水的最高高度,减去此格的空间就是这一条可以装下的水。
/**
* 支持 import Java 标准库 (JDK 1.8)
*/
import java.util.*;
import java.lang.Math;
/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
public static void main(String []args) {
int[] nums = new int[]{5,0,2,1,4,0,1,0,3};
int n = nums.length;
int[] l = new int[n];
int[] r = new int[n];
int mm = 0;
for(int i=0;i<n;i++){
mm = Math.max(mm,nums[i]);
l[i] = mm;
}
mm = 0;
for(int i=n-1;i>=0;i--){
mm = Math.max(mm,nums[i]);
r[i] = mm;
}
int ans = 0;
for(int i=0;i<n;i++){
ans += Math.max(0,Math.min(l[i],r[i])-nums[i]);
}
System.out.println(ans);
}
}
另外还有一种比较复杂的做法,单调栈,这个方法虽然复杂,但是在某些问题中的解决是一个极其优秀的算法,这类问题都有一些共同点,当前解可以与之前的结果发生作用,而之前的存储可以以一个单调栈中,每次与栈顶元素发生作用获得部分结果,而自身也需要对后续产生影响。
如果说上面的方法是竖着看,那么单调栈就是横着看,压入栈内需要考虑到两个元素,高度和index,当然index可以比较方便的获得高度,但反过来就不一样了。
如果当前height[i]比栈顶元素height[j]高,则此时加(height[i]-height[j])×(i-j)并将j出栈。 再与之前比直到遇到一个比较高的,将自己入栈。
此时最需要考虑的是如果一样高怎么算法,考虑实际情况,两个墙壁之间可以存雨滴,所以应该是需要出栈的。