当青训营遇上码上掘金--主题 4:攒青豆

94 阅读3分钟

主题4:攒青豆

题目描述

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

image.png

输入:height = [5,0,2,1,4,0,1,0,3]
输出:17 
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

题目看法

看到这道题目的时候,第一时间就想到了lc42的接雨水,两者对比之下几乎无差异。上次做这道题已经是半年前,当时虽然参照了题解进行解答,奈何那会刚学算法不久,做得云里雾里,即使最后成功提交了,但是并没有很好地理解这道题,现在再来做这道题,由于有了半年的算法铺垫,现在做起来就比较轻松了,能够很快做出来。本道题采用动态规划来解决。

题目解读

只需要算出每个位置能够攒青豆的数量,再加起来,就能得到答案,因此这道题的重点就是考虑每个位置能否攒取青豆。

每个位置能否攒青豆需要考虑以下几种情况

1.是否为边界,边界无法攒青豆

2.如果这个位置能够攒青豆,这个位置存储的青豆的数量为:左右两边分别的最大高度,其中的的较小那一个高度与这个位置高度的差值

3.如果这个位置不能攒青豆,则是因为这个位置的两边有一方小于等于这个位置的高度,无法形成高-低-高这个结构。

代码如下

* 支持 import Java 标准库 (JDK 1.8)
*/
import java.util.*;

/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
   public static void main(String []args) {
     int sum = new Main().trap(new int[]{5,0,2,1,4,0,1,0,3});
     System.out.println(sum);
   }
   
     //动态规划
   /*
    按照题意可知,能够攒下来的青豆,满足以下条件
    1.假设height[i]位置能够存储青豆,左右两边分别的最大高度其中的的较小那一个高度决定了能够攒的数量,
    2,若是height[i]这个位置无法攒青豆,
      2.1 height[i]高于等于左右两边的高度的其中一个,导致无法形成 高-低-高 的结构
      2.2 处于边界情况,边界位置无法存放
   */
    public int trap(int[] height) {
        int sum = 0;//记录青豆的数量
        int len = height.length;
        int[] leftHeight = new int[len];//记录某个位置左边的最大高度
        int[] rightHeight = new int[len];//记录某个位置右边的最大高度
        //找出某个位置左边高度的情况
        //从一开始是因为不用考虑边界的左右高度情况,
        for (int i = 1; i < len; i++) {
            //i的左边高度由i-1的左边最大高度和i-1本身的高度的最大值决定
            leftHeight[i] = Math.max(leftHeight[i - 1], height[i - 1]);
        }
        //找出某个位置的右边的高度情况
        //len-1为边界,不用考虑,因此len-2;
        for (int i = len - 2; i >= 0; i--) {
            //同样的,i的右边高度由i-1的右边最大高度和i-1本身的高度的最大值决定
            rightHeight[i] = Math.max(rightHeight[i + 1], height[i + 1]);
        }

        //比较i的左右边情况,
        //如果i的左右两边的最大有一方小于等于i的高度,那么就是无法攒青豆,跳过
        //跳过边界
        for (int i = 1; i < len - 1; i++) {
            //查看两边情况
            int min = Math.min(leftHeight[i], rightHeight[i]);
            //如果i这个位置能够攒青豆,那么攒数量由两边的较小高度决定
            if (min > height[i]) {
                //攒的数量为i和两边最小高度的高度差
                sum += min - height[i];
            }
        }
        return sum;
    }
}

时间复杂度为: O(n)

空间复杂度为: O(n)