双指针 leetcode11. 盛最多水的容器+42. 接雨水

11. 盛最多水的容器

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。
在这里插入图片描述

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例:

输入:[1,8,6,2,5,4,8,3,7]
输出:49

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题

双指针
双指针包括头指针,尾指针,一起向中心遍历;
条件为
左右指针指向的边长大的一方不动,小的一方向内遍历,若求得的面积比已保存的最大面积大,则更新最大面积;

class Solution {
public:
    int maxArea(vector<int>& height) {
        int head=0;
        int tail=height.size()-1;

        int m=min(height[tail],height[head])*(tail-head);
        while(head<tail)
        {
            if(height[head]>height[tail])	--tail;

            else       ++head;

            int t=min(height[tail],height[head])*(tail-head);
            if(m<t)		m=t;
        }
        return m;

    }
};

总结
利用双指针时,每次只移动一个指针,移动条件是比较两个指针指向数值的大小。

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

在这里插入图片描述
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trapping-rain-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

双指针方法

除了需要头尾指针遍历外,还需要额外的变量储存当前左边最高的墙和右边最高的墙;
比较头尾指针大小,小的移动;
比较移动后指针指向数值的大小和已保存的最大值大小,若更大,则更新最大值,若小,则在Sum总数里增加移动的指针已保存的最大值和当前值的差;

class Solution {
public:
    int trap(vector<int>& height) {
    
    int left=0;
    int right=height.size()-1;
    int maxleft=0;
    int maxright=0;
    int Sum=0;

    while(left<right)
    {   
        if(height[left]<height[right]){       //说明maxleft也小于right
        if(height[left]>maxleft)
            maxleft= height[left];
        else   //left高度小于左边的最大高度 
            Sum+=maxleft-height[left];
        ++left;
        }
        else {
        if(height[right]>maxright) 
            maxright=height[right];
        else
            Sum+=maxright-height[right];
        --right;
        }
    }
    
    return Sum;
    }
};

注意点
因为移动左指针的条件是左指针高度小于右指针;
故左指针的max高度一定也小于右指针,不然就会一直停在max上不动;
当移动的左指针更新了新的maxleft后,若maxleft此时大于右指针的数值,这时移动右指针;
所以当一个指针移动时,另一个指针必指向它当时的max高度,此时当前指针要加入的水量直接用当前移动指针的max高度减去当前移动指针的高度即可;

动态规划
计算每一列的高度,可由该列左右最高高度里低的那一个减去自身高度得到;

即	min(rightmax[i],leftmax[i])-height[i]; 

用动态规划求出每个点左右的最高高度,即可在N时间内完成;

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

        if(height.size()==0)
        return 0;
        vector<int> leftmax(height.size());    //存放i左边的最高墙
        vector<int> rightmax(height.size());   //存放i右边的最高墙
        leftmax[0]=height[0];
        rightmax[height.size()-1]=height[height.size()-1];
        
        for(int i=1;i<height.size();i++)
            leftmax[i]=max(leftmax[i-1],height[i]);
        
        for(int i=height.size()-2;i>=0;i--)
            rightmax[i]=max(rightmax[i+1],height[i]);

        //计算总面积
        int Sum=0;
        for(int i=0;i<height.size();i++)
            Sum+=min(rightmax[i],leftmax[i])-height[i]; 
        return Sum;
    }
};
发布了105 篇原创文章 · 获赞 6 · 访问量 4942

猜你喜欢

转载自blog.csdn.net/BLUEsang/article/details/105596857