给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:
输入:[1,8,6,2,5,4,8,3,7]
输出:49
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
思路一:优化暴力破解法
1.在示例中有类似凹槽一样的柱形图有特殊点凹点,比如2、4、3都是第一次遍历的凹点。
2.这些凹点必然被淹没,不能成为杯壁。所以我们直接排除凹点,排除凹点之后又会产生新的凹点就可重新排除。
3.直到没有凹点时,剩下的都是候选杯壁。然后就是暴力破解法了。
问题:这种方法排除了一些不必要的点,但要没有凹点的梯形排列。该方法就很鸡肋。
思路二:双指针法
思路:首先我们得出水量的计算方式为:
水量=(右杯壁下标-左杯壁下标)*min(左杯壁高度,右杯壁高度)
其中的变量有4个,这也就是我们的操作空间。
要使得水量=max,高度是没有规律可寻的,那么只有从下标动手。我们选取两端作为杯壁,然后向中间走。
可以发现(右杯壁下标-左杯壁下标)始终会减1,那么我们尽量使得min(左杯壁高度,右杯壁高度)保留最大的即可保留相对较大的水量。所以向两边走的时候我们保留高杯壁,丢弃低杯壁。直到走完就能得到所有相对较优的值,然后选取最优值就行了。
还需注意的问题:
1.双指针法是选取相对优值,再从先对优找最优。并不是一遍遍历出来就得到最优。
2.被丢弃的为什么都是劣值?因为我们每次只动用一边的指针,于是对于这一次指针移动来说另一边是固定的。固定低杯壁,移动高杯壁时水量取值必然是小于等于本次水量的。而只有固定高杯壁,移动低杯壁水量取值才有可能大于本次水量。
所以综上舍弃的必然是劣值。
以上主要考察的是思想,代码相对容易写出来。在此就不掩饰代码了。