给定n个数: a1, a2, ... , an. 代表着(i, ai)个点, 连接这些点与对应的(i, 0), 我们可以得到n条线. 请在这n条线中找出2条, 使得这两条线和x轴构成的容器能够容纳最多的水.
本题解法时间复杂度为O(n), 作者是n00tc0d3r.
我们使用2个指针从数组前后开始遍历, 每次循环都计算一次最大值.
当左侧的数比右侧的数小时, 左指针向右挪动一格, 否则, 右指针向左挪动一格.
直到两个指针相遇, 算法结束.
1 class Solution { 2 public: 3 int maxArea(vector<int> &height) { 4 if (height.size() < 2) return 0; 5 int maxA = 0; 6 int low = 0, high = height.size() - 1; 7 while (low < high) { 8 int A = (high - low) * min(height[low], height[high]); 9 maxA = max(A, maxA); 10 if (height[low] < height[high]) 11 low++; 12 else 13 high--; 14 } 15 return maxA; 16 } 17 };
数学证明:
给定a1,a2,a3.....an为输入数组,假设a10和a20是最大面积解,我们需要证明的是左指针指向a10时右指针有机会指向a20. 即证明:当左指针指向a10,右指针指向a21时,下一步一定是移动右指针到a20。
因为永远移动的是较小的一边,分为2种情况,如果a10 > a21,应该移动a21到a20,证毕;如果a10 < a21,那a10和a21的面积至少是a10 * 11,而a10和a20的面积最多是a10 * 10(因为a10小于a21,即使a20大于a10,面积依旧是a10 * 10,如果a20小于a10,则面积小于a10 * 10),从而a10和a21是最优解,和我们的假设矛盾。
综上, 算法返回值必定是最优解.
英文原版说明:
[Given a1,a2,a3.....an as input array. Lets assume a10 and a20 are the max area situation. We need to prove that a10 can be reached by left pointer and during the time left pointer stays at a10, a20 can be reached by right pointer. That is to say, the core problem is to prove: when left pointer is at a10 and right pointer is at a21, the next move must be right pointer to a20.
Since we are always moving the pointer with the smaller value, i.e. if a10 > a21, we should move pointer at a21 to a20, as we hope. Why a10 >a21? Because if a21>a10, then area of a10 and a20 must be less than area of a10 and a21. Because the area of a10 and a21 is at least height[a10] * (21-10) while the area of a10 and a20 is at most height[a10] * (20-10). So there is a contradiction of assumption a10 and a20 has the max area. So, a10 must be greater than a21, then next move a21 has to be move to a20. The max cases must be reached.
]