问题描述
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container.
问题分析
木桶装水问题,乍一想要符合木桶效应:一只水桶能装多少水取决于它最短的那块木板。这里要从数组列表中找到两块“木板”能围住的最大面积(以较低的木板为高)。
- 一开始想到的解决方案也是最省事儿的办法就是针对每条“木板”i找到比它高的木板中离它最远的那条j,i和j围住的区域则是i木板所能围住的最大面积,每条木板都需要扫描n次,所以其算法复杂度为n^2.然后运行就提示超时了。见代码:
class Solution {
public:
int maxArea(vector<int> &height) {
vector<int> p(height.size(), 0);//记录每条木板对应的"最远木板"
for (int i = 0; i < height.size(); i++){
for (int j = 0; j < height.size(); j++){
if (j != i && height[i] <= height[j]){
if (p[i] < abs(j - i)){
p[i] = abs(j - i);
}
}
}
}
int ans = 0;
for (int i = 0; i < height.size(); i++){
int area = height[i] * p[i];
if (area > ans) ans = area;
}
return ans;
}
};
- 随后在草纸上模拟,当我画出如下图的时候,算法也自然就出来了,复杂度为O(n).
举例:height数组为{2,3,8,5,6,1},这里以坐标0起始。
可以看出,我们只要从两端向中间扫描,每次留长弃短即可,特殊情况两板相同则同时舍弃。
附accept代码:
class Solution {
public:
int maxArea(vector<int> &height) {
int i=0,j=height.size()-1;
int ans = 0;
int area;
while (i < j){
if (height[i] < height[j]){
area = (j - i) * height[i];
i++;
}
else if (height[i] > height[j]){
area = (j - i) * height[j];
j--;
}
else {
area = (j - i) * height[j];
i++; j--;
}
if (area > ans) ans = area;
}
return ans;
}
};