LeetCode第 11 题:盛最多水的容器(C++)

11. 盛最多水的容器 - 力扣(LeetCode)

盛水就是理解为面积的意思吧,令i, j表示数组中元素的下标,对应的矩形长为 j − i j-i ji,高为 m i n ( a i , a j ) min(a_i, a_j) min(ai,aj),最多盛水即为矩形面积 ( j − i ) ∗ m i n ( a i , a j ) (j-i)*min(a_i, a_j) (ji)min(ai,aj)

容易让人想到滑动窗口或者双指针,每一对(i,j)都会对应一个面积,我们需要的是最大的面积,如果使用暴力求解,需要对每一个 i 都尝试i后面所有的 j ,时间复杂度为O(n^2)。

暴力法的代码很简单:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int area = 0;
        for(int i = 0; i < height.size(); ++i){
            for(int j = i+1; j < height.size(); ++j)
                area = max(area, (j-i)*min(height[i], height[j]));
        }
        return area;
    }
};

但是会在倒数第二个测试用例上超过时间限制,说明需要进行优化。我们不能对i后面的每一个j都进行计算,那就优化一下:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int area = 0;
        int left = 0; //用于记录当前最大的左边界
        for(int i = 0; i < height.size(); ++i){
            if(height[i] < height[left])    continue;
            int right = height.size()-1;//用于记录当前最大的右边界
            for(int j = height.size()-1; j > i; --j){//从最右边开始
                if(height[j] < height[right])   continue;
                area = max(area, (j-i)*min(height[i], height[j]));
                cout << i << " " << area << endl;
                right = j;
            }
            left = i;
        }
        return area;
    }
};

进行了部分优化,可以提交通过,但是效率一般,而且时间复杂度还是没变,依然是两层循环,两次遍历

有没有一次遍历就可以的思路呢?我们还可以从两边往中间移动,不停地缩小窗口,设i,j分别是左右窗口边界

  • 如果height[i] <= height[j]:area = (j-i)*height[i],然后–i
  • 如果height[i] > height[j]:area = (j-i)*height[j],然后–j

i = = j i == j i==j的时候,计算结束。

class Solution {
public:
    int maxArea(vector<int>& height) {
        int area = 0;
        int i = 0, j = height.size()-1; //分别是窗口的左右边界
        while(i < j){
            if(height[i] <= height[j])
                area = max(area, (j-i)*height[i++]); 
            else
                 area = max(area, (j-i)*height[j--]);
        }
        return area;
    }
};

时间复杂度是O(n),一次遍历,运行效率直接起飞,上述代码还可以简化一下,三行代码:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int area = 0, i = 0, j = height.size()-1; //分别是窗口的左右边界
        while(i < j)	area = (height[i] <= height[j]) ? max(area, (j-i)*height[i++]) : max(area, (j-i)*height[j--]);
        return area;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值