青训营 X 码上掘金 | 攒青豆

76 阅读1分钟

当青训营遇上码上掘金

问题定义

主题4-攒青豆:有n个宽度为1的柱子,给出n个非负整数依次表示柱子的高度,此时均匀从上空向下撒青豆,计算排列的柱子能接住多少青豆。

image.png 例如上图,输入是记录柱子高度的数组:height = [5,0,2,1,4,0,1,0,3] ,输出:17。

问题分析

和接雨水的问题一样,有很多种解法,这里介绍两种解法:暴力解法和双指针解法。

暴力解法

暴力解法思路:

  • 每个柱子能接多少青豆取决于它左右两边柱子的最小高度
  • 求解当前柱子左右两边最大高度比较后的最小值减去当前柱子的高度就是每个柱子能接的青豆
  • 第一个柱子和最后一个柱子接不住青豆不必计算
  • 计算左右最大高度范围包括当前柱子高度

代码如下:

public static int getBeanByForce(int[] height) {
      int n = height.length;
      int res = 0;
      int[] leftMax = new int[n];
      int[] rightMax = new int[n];
      leftMax[0] = height[0];
      rightMax[n - 1] = height[n - 1];
      for (int i = 1; i < n; i++) {
        leftMax[i] = Math.max(leftMax[i - 1], height[i]);
      }
      for (int i = n - 2; i >= 0; i--) {
        rightMax[i] = Math.max(rightMax[i + 1], height[i]);
      }
      for (int i = 0; i < n; i++) {
        res += Math.min(leftMax[i], rightMax[i]) - height[i];
      }
      return res;
   }

双指针解法

双指针解法思路:

  • 左右指针分别指向数组开头和结尾
  • 当左指针指向的柱子高度小于右指针指向的高度时:判断左指针指向的柱子高度是否比左指针经过的最高的柱子高。如果高那么更新左指针遍历过的最大柱子高度,否则累计可接住的青豆(即左指针遍历过的最大柱子高度 - 当前柱子高度)。经历上述操作后,左指针++,向数组末尾移动
  • 当左指针指向的柱子高度大于等于右指针指向的高度时:判断右指针指向的柱子高度是否比右指针经过的最高的柱子高。如果高那么更新右指针遍历过的最大柱子高度,否则累计可接住的青豆(即右指针遍历过的最大柱子高度 - 当前柱子高度)。经历上述操作后,右指针--,向数组开头移动
  • 重复第2,3点直到左指针大于等于右指针

代码如下:

public static int getBeanByPoints(int[] height) {
    int left = 0;
    int right = height.length - 1;
    int res = 0;
    int leftMaxHeight = 0;
    int rightMaxHeight = 0;
    while (left < right)
    {
      if (height[left] < height[right])
        {
          if (height[left] > leftMaxHeight)
            leftMaxHeight = height[left];
          else
            res += leftMaxHeight - height[left];
          left++;
        }
      else
        {
          if (height[right] > rightMaxHeight)
            rightMaxHeight = height[right];
          else
            res += rightMaxHeight - height[right];
          right--;
        }
    }
    return res;
   }

总结

以上就是青训营码上掘金主题4-攒青豆的两种解法啦!