当青训营遇上码上掘金-攒青豆-项目4

77 阅读2分钟

题目描述:

现有 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)