算法分析与设计——LeetCode Problem.11 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.

题目已经给出了一个c++的框架

class Solution {
public:
    int maxArea(vector<int>& height) {

    }
};

问题分析与思路

题意是让我们将一个vector数组想像成一个方形2d水桶,水桶以vector数组中的两个数为左右两边,以这两个数在vector数组中的距离为底。
这道题可以说一个刚学习c语言的人也能做出来,只需要使用c语言里最基础的冒泡算法,再查查vector的用法就能解决掉。

但是!

这里有一个问题,冒泡算法的算法复杂度是O(n2 ),而这样的算法复杂度用来解决这样一道题在我看来十分浪费!
因此我开始思考,水桶的装水面积是由短的那条边,乘以底边,而我们需要找出装水面积的最大值,那么我们只需要考虑需要乘积的两条边的值。而其中底边的最大值自然是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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章