当青训营遇上码上掘金
主题介绍
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思路讲解
1、暴力解法
看到这道题,我凭直觉首先想到的就是暴力解法。
即从左向右遍历数组,对每个柱子求左边的最大高度的柱子和右边的最大高度的柱子,取两者最小值减去当前柱子的高度,就是当前柱子能接住的豆子。遍历得到所有柱子能接住的豆子之和就是答案。
但是暴力解法时间复杂度为n^2,一般对于此类算法问题我们都追求更低的时间复杂度,于是就有了下面的双指针解法。
2、双指针法
- 什么是双指针法?
双指针法是一种常用的算法技巧,常常用在数组和字符串等问题。它通过使用两个指针来同时遍历数组。每个指针朝着一个方向移动,可以指针朝同一个方向走,一个指针快,一个指针慢;可以指针朝相对方向走,初始化一个指向数组头部,一个指向数组尾部。
我自己使用双指针法解决了数组去重、链表操作、寻找回文字符串、最长子数组和等等问题,双指针法可以帮助解决许多问题,是一种高效的算法。
- 那么对于这道题使用双指针法的详细思路是什么?
1、定义两个指针left和right分别指向数组的开头和末尾,同时初始化两个变量leftmax和rightmax来存储左右柱子的最大高度。
2、每次移动指向较小值的指针,直到left和right相遇
3、当left < right时,执行循环:
如果left指向的柱子的高度小于right指向的柱子的高度,那么以left指向的柱子为下边界的容器可以接住青豆。如果当前left指向的柱子的高度大于等于leftmax,更新leftmax;否则,累加青豆数。最后left++。
否则,如果right指向的柱子的高度小于等于left指向的柱子的高度,那么以right指向的柱子为下边界的容器可以接住青豆。如果当前right指向的柱子的高度大于等于rightmax,更新rightmax;否则累加青豆数。最后right--。
循环结束后,返回累加青豆数。
- 这里需要注意的地方是
- 每个柱子宽度为1,所以能装的青豆数是边界最小值减去当前柱子高度即可
- 左边最大值leftmax,因为左边只有小于height[right]才会更新leftmax,所以leftmax肯定比height[right]小,即左边界肯定比右边界小,所以计算可装的青豆数用左边界来减,即sum += leftmax - height[left]。右边最大值rightmax同理。