[路飞] 盛水最多的容器

382 阅读3分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。

记录 1 道算法题

盛水最多的容器

leetcode-cn.com/problems/co…


给一个柱状图,柱子的 x 坐标之间的距离为 X,两个柱子中最低的那个柱子的 y 坐标决定 Y,像木桶原理那样,由最短的那块板决定。然后求出在这么多个柱子中组合出的最大的容积 X * Y。

最佳的解法是双指针,从一头一尾,往中间压缩。每次移动 X 是递减。我们遍历一遍,直到让两个指针交叉,然后通过比较每次遍历到的柱子的面积得到最大的 X * Y。

区间的问题用指针是比较好解决的,但是问题是如何判断我们该移动左指针还是右指针。

假设我们要给一个期望移动会产生更大值,当两个柱子 left 和 right 和他们的指针 leftX,rightX, left 小于 right。

  1. 当我们移动 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 的时候,有可能出现最大值。

  1. 当我们移动 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
    }