https://leetcode.com/problems/container-with-most-water/
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 and n is at least 2.
The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
Example:
Input: [1,8,6,2,5,4,8,3,7] Output: 49
这道题一开始很自然地想到的是单调栈的方法。在容器右壁确定的情况下,分析每一个容器左壁的性质有,任何一个柱右侧的不高于它的柱都不可能(作为左壁)提供更大的容积,因此维护一个壁高的单调数组(其实也不能说是栈,因为只进不出),对于每一个新来的壁如果他比当前的最高壁更高则添加到数组末尾,否则丢弃。
但是对于容器右壁,需要对原始数据中的每一个位置进行遍历并根据当时的上述单调数组中的值选择相应的最大容量左壁。考虑到容器的宽有时候能够提供比高更多的容积(如1 1 1.... 1 5 1),因此不能简单使用二分查找的方法选择“最大限度地利用右壁的高度”的位置,而需要至少从低到高遍历判断到这个位置。
class Solution {
public:
int maxArea(vector<int>& height) {
static int fast_io = []() { std::ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
vector<int> y;
vector<int> x;
y.push_back(0);
x.push_back(-1);
int result = 0;
int flag = 0;
for(int i = 0; i < height.size(); ++i){
flag = 0;
for(int j = 1; j < y.size(); ++j){
if(y[j] > height[i]){
if(flag == 0) ++flag;
else break;
}
result = max(result, min(y[j], height[i])*(i-x[j]));
}
if(height[i] > y.back()){
y.push_back(height[i]);
x.push_back(i);
}
}
return result;
}
};
但是这个方法的复杂度太高,时间用到了340ms,显然是不理想的。
很明显导致复杂度的原因在于针对每一个右壁的选择对左壁需要进行遍历的关系(在最坏情况下就相当于枚举两壁的所有组合了),考虑对单调结构的维护添加一定的出操作,但是很难想明白。
看了别人的答案才发现其实可以将右壁使用和左壁同样的思路(其实回过头来看是很显然的,因为这个问题本身就具有很强的对称性),同时由于这个所谓的单调数组并没有“出”这个操作所以 但是需要做一定的修改,不把两壁分开考虑,作为整体之后就很明显了单调性在于两壁收拢时桶的宽度减小,欲使容积增大,桶高必须增加。(感觉很好理解,但说不明白)
class Solution {
public:
int maxArea(vector<int>& height) {
static int fast_io = []() { std::ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
int lo = 0;
int hi = height.size()-1;
int hei;
int result = 0;
while(lo < hi){
hei = min(height[lo], height[hi]);
result = max(result, hei*(hi-lo));
while(lo < hi && height[lo] <= hei) ++lo;
while(lo < hi && height[hi] <= hei) --hi;
}
return result;
}
};