青训营 X 码上掘金 主题4:攒青豆

61 阅读2分钟

当青训营遇上码上掘金

题目

主题 4:攒青豆

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

42ca386c02b98ab9984220754f8fcd8.jpg

输入: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.*;

/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
   public static void main(String []args) {
        
        int[] heights={5,0,2,1,4,0,1,0,3};
        System.out.println(Solve(heights));
   }
   public static int Solve(int[] heights) {
        //左指针
        int left = 0;
        //右指针
        int right = heights.length - 1;

        int max_l = 0;
        int max_r = 0;
        
        int sum = 0;

        //两指针分别从左、右向中间遍历
        while (left != right) {
            //右边柱子高,就以左边短柱子接到的豆子
            //第一遍:left=5,right=3,max_r=3,sum=3
            //第二遍: left=5,right=0,max_r=3,sum=5
            //...
            //找左右柱子小的下一个凹槽加起来
            if (heights[left] < heights[right]) {
                if (heights[left] >= max_l) {
                    max_l = heights[left];
                }
                
                sum += max_l - heights[left++];
            }
            if (heights[right] >= max_r) {
                max_r = heights[right];
              }
              sum += max_r - heights[right--];
            }

        
        return sum;
    }
}