最朴素的想法就是,枚举容器的左边界和右边界,总能找到解,不过时间复杂度是O(n^2)的。
改进I:从左向右枚举左边界,在此基础上从右向左枚举右边界,一旦右边界高度>=左边界高度就可以停止枚举了,因为继续枚举下去找到的矩形肯定面积更小。
比如下图,左边界在位置0,高度为height[0]=3,那么,右边界枚举到位置5就可以停止了(height[5]=4 >= 3=height[0])。
|
| |
| | |
| | | | | |
| | | | | | |
+-+-+-+-+-+-+
0 1 2 3 4 5 6
^ ^
左边界 右边界
改进II:
在改进I中,要从左到右枚举左边界,但是左边界是否要一直枚举到最右边呢?当然不是。
看下图,假设现在枚举到了这个位置:左边界高度是2,右边界高度也是2。
|
| |
| | |
| | | | | |
| | | | | | |
+-+-+-+-+-+-+
0 1 2 3 4 5 6
^ ^
左边界 右边界
那么,左边界在以后向右移动的时候,凡是高度小于等于2的位置都不用考虑了(图中位置3、4),因为肯定不会超过当前这个矩形的面积。
所以,每次枚举的时候根据右边界高度更新这个阈值,以后遇到阈值低于这个的左边界就不用考虑了。
改进III
在改进II中,先确定左边界,然后去枚举右边界,同时右边界又对左边界的选择有一定影响。仔细想想,左右边界本身没有区别,所以可以从两头分别开始枚举,更新阈值。如果左边界比右边界矮,左边界决定了最终矩形的高度,以后不会再有比这个矩形矮并且面积更大的矩形出现了,所以让左边界向右移动一个单位。同理如果右边界比左边界矮,右边界向左移动一个单位。
这就是最终的算法了。
代码:
1 int maxArea(vector<int> &height) { 2 int l = 0; 3 int r = height.size() - 1; 4 int res = 0; 5 6 while (l <= r) { 7 res = max(res, (r - l) * min(height[l], height[r])); 8 if (height[l] < height[r]) 9 l++; 10 else 11 r--; 12 } 13 14 return res; 15 }