LeetCode 42. Trapping Rain Water【接雨水+左右遍历动态规划】⭐⭐⭐⭐⭐

题目描述

在这里插入图片描述

知识点

思维+动态规划

结果

在这里插入图片描述

实现

码前思考

  1. 之前我使用了一种错误的思想去思考这个问题。。。
  2. 后来看了LeetCode官方题解才发现,原来一个点的积水量,就是取决于它左边最高高度和右边最高高度的最小值。。。
  3. 这样的话,就很好写代码了。

代码实现

//动态规划,类似于合唱队形,只不过是凹陷的,求面积
class Solution {
public:
    int trap(vector<int>& height) {
        int size = height.size();
        if(size==1||size==0){
            return 0;
        }
        vector<int> left(size,0);
        vector<int> right(size,0);
        //从左往右,找递减
        left[0]=height[0];
        for(int i=1;i<height.size();i++){
            if(height[i]<left[i-1]){//必须是严格小于不能等于
                left[i]=left[i-1];
            }else{
                left[i]=height[i];
            }
        }

        //从右到左,找递减
        right[size-1]=height[size-1];
        for(int i=size-2;i>=0;i--){
            if(height[i]<right[i+1]){
                right[i]=right[i+1];
            }else{
                right[i]=height[i];
            }
        }

        //遍历两个数组,找到最低点
        int res=0;
        for(int i=0;i<size;i++){
            int minHeight = min(left[i],right[i]);
            res+=minHeight-height[i];
        }

        return res;
    }
};

码后反思

  1. 我还是太天真了。。。

错误代码,考虑以区域为单位就算,忽视了高高低低的情况

//动态规划,类似于合唱队形,只不过是凹陷的,求面积
class Solution {
public:
    int trap(vector<int>& height) {
        int size = height.size();
        if(size==1||size==0){
            return 0;
        }
        vector<int> left(size,0);
        vector<int> right(size,0);
        //从左往右,找递减
        left[0]=0;
        for(int i=1;i<height.size();i++){
            if(height[i]<height[i-1]){//必须是严格小于不能等于
                left[i]=left[i-1];
            }else{
                left[i]=i;
            }
        }

        //从右到左,找递减
        right[size-1]=size-1;
        for(int i=size-2;i>=0;i--){
            if(height[i]<height[i+1]){
                right[i]=right[i+1];
            }else{
                right[i]=i;
            }
        }

        //遍历两个数组,找到最低点
        int res=0;
        for(int i=0;i<size;i++){
            if(left[i]!=i&&right[i]!=i){//说明是一个最低点
                printf("当前是:%d\n",i);
                printf("当前是:%d\n",left[i]);
                printf("当前是:%d\n",right[i]);
                //首先得到两边最短的
                int lHeight = height[left[i]];
                int rHeight = height[right[i]];
                int minHeight;
                int lBound;
                int rBound;

                if(lHeight > rHeight){
                    minHeight = rHeight;
                    //从右到左,找第一个大于等于这个的
                    rBound=right[i];
                    for(lBound=i-1;lBound>=left[i]&&height[lBound]<height[rBound];lBound--);
                }else{
                    minHeight = lHeight;
                    //从左到右,找第一个大于等于这个的
                    lBound=left[i];
                    for(rBound=i+1;rBound<=right[i]&&height[rBound]<height[lBound];rBound++);
                }
                //计算一个大的面积
                int tot = (rBound-lBound-1)*minHeight;
                for(int j=lBound+1;j<=rBound-1;j++){
                    tot-=height[j];
                }
                res+=tot;
            }
        }

        return res;
    }
};

二刷反思

要仔细考虑清楚问题的特征,某一点的积水量,就是取决于它左边最高高度和右边最高高度的最小值。。。

//为了得到不重复的结果,需要强制只能使用自己后面的元素,一种典型的dfs暴力方法
//相似的题目还有之前那个求最短的
class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        int len = candidates.size();
        dfs(candidates,target,0);
        return res;    
    }

    void dfs(vector<int>& candidates,int target,int idx){
        if(target==0){//不需要求和了
            res.push_back(path);
        }else if(target<0){
            return;//小于0肯定不行
        }else{
            for(int i=idx;i<candidates.size();i++){
                path.push_back(candidates[i]);
                dfs(candidates,target-candidates[i],i);
                path.pop_back();
            }
        }
    }

};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值