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

46 阅读2分钟

当青训营遇上码上掘金

成功在一小时内参与进活动了,差点青豆就飞了,话不多说,进入正题。

主题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 个单位的青豆。

思路

这题和力扣的接雨水很像,实际上要想知道当前节点可以攒多少青豆,需要知道该节点左边所有节点中最大值以及所有右边节点中的最大值,然后该节点可以攒的青豆多少就由左右两个节点中较小的那个节点决定,较小节点减去当前节点就是该节点的可攒最大青豆数,然后累加所有节点可攒最大青豆数即可得出结果,有点类似木桶效应,考虑到时间复杂度,如果对于每个节点都遍历一遍其左右节点最大值,则时间复杂度为O(n^2),所以可以牺牲一下空间,用两个数组,一个数组盛放每一个节点的左节点中最大值,另一个数组盛放每一个节点的右节点中最大值,然后遍历原数组,即可计算出结果,且时间复杂度为O(n)。

测试代码

import java.util.*;
public class Main {
   public static void main(String []args) {
       //test数组内容可以修改
      int []test = {5,0,2,1,4,0,1,0,3};
      int len = test.length;
      int[] lmax = new int[len];
      int[] rmax = new int[len];
      int maxl = test[0];
      int maxr = test[len - 1];
      for(int i = 0; i < len; i++){
        if(maxl < test[i]) maxl = test[i];
        lmax[i] = maxl;
      }
      for(int i = len -1; i >= 0; i--){
        if(maxr < test[i]) maxr = test[i];
        rmax[i] = maxr;
      }
      int ans = 0;
      for(int i = 0; i < len; i++){
        int min = lmax[i] > rmax[i] ? rmax[i] : lmax[i];
        ans += min - test[i];
      }
      System.out.println(ans);
   }
}