「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。
记录 1 道算法题
盛水最多的容器
给一个柱状图,柱子的 x 坐标之间的距离为 X,两个柱子中最低的那个柱子的 y 坐标决定 Y,像木桶原理那样,由最短的那块板决定。然后求出在这么多个柱子中组合出的最大的容积 X * Y。
最佳的解法是双指针,从一头一尾,往中间压缩。每次移动 X 是递减。我们遍历一遍,直到让两个指针交叉,然后通过比较每次遍历到的柱子的面积得到最大的 X * Y。
区间的问题用指针是比较好解决的,但是问题是如何判断我们该移动左指针还是右指针。
假设我们要给一个期望移动会产生更大值,当两个柱子 left 和 right 和他们的指针 leftX,rightX, left 小于 right。
- 当我们移动 leftX 指针的时候。
leftX 指针可能会指向一个比原来大的值或者比原来小的值。但是我们知道,y 坐标是取两者之间的最小值,所以假如移动后的 left 比 right 大,则 Y 取 right,由于 right 大于移动前的 left,所以由于 Y 增大了,面积增大了。我们得到的期望是会出现更大值。
-
假如移动后的 left 比 right 小,这时候就要看移动前后的 left 谁更大。假设移动前的小一点,我们会得出由于之前的 Y 是取 left 的值,所以随着 left 增大,Y 也增大了,但没有超过 right,所以 Y 仍然是取 left 的值。
所以当移动前的 left 比 移动后的 left 小时,我们得到的期望是会出现更大值。假设移动前大一点,我们会得出由于最短的那个柱子变小了,整体的面积也会变小。
所以当移动前的 left 比 移动后的 left 大时,我们得到的期望是不会出现更大值。
所以我们最好移动下一位比当前值小的指针,但也毕竟不会知道下下个有多大,所以只从是得出了这种情况下 left 小于 right 时,移动 left 的时候,有可能出现最大值。
- 当我们移动 rightX 指针的时候。
rightX指针可能指向一个比原来大或者小的值。但是 Y 是取 left 的值。所以 right 变大丝毫不影响面积的大小,不符合期望。
但是如果 right 移动后,比 left 还小,这时候 Y 的取值就变成了 right,也变得更小,我们得到的期望是不会出现更大值。
所以我们最好移动两个指针中最小的那一个,即改变最短的木板,希望会获得更长的木板
function maxArea(height) {
let a = 0
let b = height.length - 1
let result = 0
while(a < b) {
const left = height[a]
const right = height[b]
const x = b - a
const y = Math.min(left, right)
// 比较每次遍历的结果
result = Math.max(result, x * y)
if (left < right) {
left++
} else {
right--
}
}
return result
}