题目描述:
给你 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,要想使得结果有可能变大,只能尽量增高,移动矮的一侧对应的指针。
这里或许会使人产生一个疑问,即在当前这一步做出局部最优解的情况下,有没有可能错过全局最优解?举个例子,如果一开始右指针从size()-1左移,全局最优解的右指针有没有可能是size()-1? 用反证法这样来分析:一开始右指针左移说明一开始右指针是更小的,假设全局最优解的左指针最终比这个右指针小,那么将产生矛盾,因为这样的全局最优解宽度小于一开始的宽度且最短侧的高度也小于开始的高度;假设全局最优解的左指针更大,那么全局最优解的右指针作为容器的高,而最开始时容器容积的高也是右指针且宽度大于全局最优解,也产生矛盾,因此,一开始将右指针左移,是不会错过全局最优解的。
每一次移动后产生的子问题都是一样的考虑模式,且左右指针是对称的,所以采用这样的做法是不会错过全局最优解的。
参考代码:
int maxArea(vector<int>& height) {
int ans = 0;
int size = height.size();
int left = 0, right = size - 1;
while(left < right){
ans = max(ans, (right - left) * min(height[left], height[right]));
if(height[left] < height[right]) left++;
else right--;
}
return ans;
}