问题详情
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.
题目已经给出了一个c++的框架
class Solution {
public:
int maxArea(vector<int>& height) {
}
};
问题分析与思路
题意是让我们将一个vector数组想像成一个方形2d水桶,水桶以vector数组中的两个数为左右两边,以这两个数在vector数组中的距离为底。
这道题可以说一个刚学习c语言的人也能做出来,只需要使用c语言里最基础的冒泡算法,再查查vector的用法就能解决掉。
但是!
这里有一个问题,冒泡算法的算法复杂度是O(
因此我开始思考,水桶的装水面积是由短的那条边,乘以底边,而我们需要找出装水面积的最大值,那么我们只需要考虑需要乘积的两条边的值。而其中底边的最大值自然是vector的大小减1。
因此我先从底边最大开始考虑,让底边依次变小,这可以保证底边的长度从最大到最小都能被考虑到,且底边的两个端点可能是vector中的任意两个端点!
然后就考虑底边如何变小的过程,由于我们的装水面积是底边乘以左右两边中小的那一个数,且每次端点变化时底边长度减1,因此如果要让后面的装水面积有可能大于前面的装水面积,我们必须留下左右两边中较大的那一个数!然后将左右两边较小的数的端点移动,使得底边变小。
这个算法保证了底边的端点可能是数组中任意两个位置。同时底边每次变小时都保留了较长边,保证不会再次使用上次计算面积时的较小边。因此他找出来的一定是最大面积。
以上是算法的核心思路。这样从左右依次靠近的算法由于只遍历了一次vector数组,因此他的时间复杂度是O(n)!比冒泡算法改进了太多了!
具体代码
class Solution {
public:
int maxArea(vector<int>& height) {
int max = 0, LeftEdge = 0, RightEdge = height.size() - 1;
int now = 0;
while(LeftEdge != RightEdge) {
if(height.at(LeftEdge) >= height.at(RightEdge)) {
now = height.at(RightEdge) * (RightEdge - LeftEdge);
}
else {
now = height.at(LeftEdge) * (RightEdge - LeftEdge);
}
if(max < now) {
max = now;
}
if(height.at(LeftEdge) > height.at(RightEdge))RightEdge--;
else LeftEdge++;
}
return max;
}
};