青训营 | 主题 4 攒青豆

41 阅读2分钟

当青训营遇上码上掘金

题目

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

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

QQ截图20230214181830.png

这是类似经典的计算雨水问题的问题。我们可以使用双指针法来解决。

具体做法是从两端分别向中间移动指针,维护左右两端的最大高度,每次比较左右两端的最大高度,将较小的那个减去当前柱子的高度就是当前柱子能接的青豆数量。依次计算每个柱子能接的青豆数量,累加起来即可得到总共能接的青豆数量。时间复杂度为 O(n)。

以下是javaScript 代码实现:


function trap(height) {
  // 左右指针
  let left = 0, right = height.length - 1;
  // 左右两根最大柱子的高度
  let leftMax = 0, rightMax = 0;
  // 总的豆子数量
  let ans = 0;
  // 移动指针(当左指针小于右指针时)
  while (left < right) {
    // 当左边柱子的高度 < 右边柱子的高度时 
    if (height[left] < height[right]) {
      // 移动左边的指针
      if (height[left] > leftMax) {
        leftMax = height[left];
      } else {
        ans += leftMax - height[left];
      }
      left++;
    } else {
      // 移动右边的柱子指针
      if (height[right] > rightMax) {
        rightMax = height[right];
      } else {
        ans += rightMax - height[right];
      }
      right--;
    }
  }
  return ans;
}

运行流程解析

第一次:
leftMax = 0; left = 0; rightMax = 3; right = 7; ans = 0;

第二次:
leftMax = 0; left = 0; rightMax =3; right = 6; ans = 3;

第三次:
leftMax=0; left = 0; rightMax = 3; right = 5; ans = 5;

第四次:
leftMax=0; left = 0; rightMax = 3; right = 4; ans = 8;

第五次:
leftMax=0;left = 0; rightMax = 4; right = 3; ans = 8;

第六次:
leftMax=0;left=0;rightMax=4; right = 2; ans = 11;

第七次:
leftMax=0;left=0;rightMax=4; right=1; ans = 13;

第八次:
leftMax=0;left=0;rightMax=4; right=0;ans = 17;

第九次:
leftMax=0;left=0;rightMax=5;ans = 17;

结束

码上掘金链接:code.juejin.cn/pen/7199948…