题目
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.
题目来源:https://leetcode.com/problems/container-with-most-water/
分析
若干根直线,求两根直线之间组成容器的最大容量。
首先,容器的高度取决于这两根线中较小的一根。与中间的线的高矮无关。
例如:1,2,1,3。当取2和3时,容量最大。
这道题和Largest Rectangle in Histogram是不一样的。
解法:
取left指针和right指针,从两头开始,往中间靠拢。如果靠拢的过程中发现height变小了就完全没必要算了,因为靠拢过程过程中宽度变小,如果高度再变小容量肯定变小。用两重循环直接暴力算也可以,复杂度是O(n^2)。
优化:
为了加快,可以先遍历一遍,暂存每个height右边第一个比它大的元素的下标,暂存每个height左边第一个比它大的元素的下标。这样双重循环是速度就能快一点。
代码
class Solution {
public:
int maxArea(vector<int>& height) {
int n = height.size();
int *help_left = new int[n];
int *help_right = new int[n];
help_left[0] = -1;
help_right[n-1] = n;
for(int i = 1; i < n; i++){
int j = i-1;
while(height[i] > height[j] && j != -1) j = help_left[j];
help_left[i] = j;
}
for(int i = n-2; i >= 0; i--){//这个也循环可以和上面的循环糅合成一个,一次遍历就可以了。
int j = i + 1;
while(height[i] > height[j] && j != n) j = help_right[j];
help_right[i] = j;
}
int max_area = 0;
for(int left = 0; left < n; ){
for(int right = n-1; right > left; ){
int h = min(height[left],height[right]);
int area = h * (right - left);
if(area > max_area)
max_area = area;
if(help_left[right] > left)
right = help_left[right];
else
break;
}
if(help_right[left] < n)
left = help_right[left];
else
break;
}
return max_area;
}
};