题目描述
给定 n 个非负整数 a1,a2,…an,表示平面上有 n 条竖线,第 i 条竖线的两个端点是 (i,ai) 和 (i,0)。请找出两条竖线,使得它们与 x 轴组成的容器能盛最多的水。
注意:不可以把线倾斜,并且 n≥2。
算法
(指针扫描) O(n)
这题的思路比较精巧,我们先给出做法,再给出证明。
做法:用两个指针 i,j 分别指向首尾,如果 ai>aj,则 j\-\-;否则 i++,直到 i=j 为止,每次迭代更新最大值。
证明:假设最优解对应的两条线的下标是 i′,j′(i′<j′),在 i,j 不断靠近的过程中,不妨假设 i 先走到 i′,则此时有 j′<j。反证,如果此时 ai≤aj,设 S 表示 i,j能盛多少水,S′ 表示 i′,j′ 能盛多少水,则:
S=min(ai,aj)∗(j−i)
=ai∗(j−i)
>ai∗(j′−i)
≥min(ai,aj′)∗(j′−i)=S′
与 S′ 是最优解矛盾,因此 ai>aj,所以 j 会一直走到 j′,从而得到最优解。
时间复杂度分析:两个指针总共扫描 n 次,因此总时间复杂度是 O(n).
C++ 代码
class Solution {
public:
int maxArea(vector<int>& height) {
int res = 0;
for (int i = 0, j = height.size() - 1; i < j; )
{
res = max(res,
min(height[i], height[j]) * (j - i));
if (height[i] > height[j]) j -- ;
else i ++ ;
}
return res;
}
};
双指针,如果nums[i] <= nums[j],那么(i, j) , (i, j - 1), (i, j - 2), .... (i, i + 1)这些范围相当于都考虑过了,并且area就是(i,j)时的面积,所以 i 已经没必要存在了,我们让 i++
一语惊醒梦中人
orz
#### 为之后臭名昭著的”接雨水”埋下伏笔
y总最后的为啥是min(ai,aj′)∗(j′−i)=S’?不是min(ai’, aj’)*(j’-i’)=S’吗?
“ 不妨设i先走到i’ ”,此时i和i’是一样的。是先固定下左边的指针再去考虑右边的性质吧,如果两个指针都在动应该很难想到做法(也可能是因为我菜orz)
对滴。
Mark 下我能看得懂的证明~
好滴~
没有看懂你在证明什么,还麻烦能不能在详细解释一下?另外还有个疑问,就是如果两个指针h[i]==h[j]的时候,应该怎么走?它有几种情况i++,j 或者是i,j–,这种情况烦请解释一下。
在证明上述做法一定可以得到最优解。从上述证明中可以看出,如果
h[i] == h[j]
,那么移动哪个指针都是可以的。ps:上面的证明写得相当清楚啊。。在数学上一般都是这么证明的,只是抽象符号比较多,同学你要慢慢习惯啊。