《写题记录》灌溉花园的最少水龙头数目

文章讲述了两种C++实现方法来解决计算最少需要开启多少个水龙头才能覆盖整个花园的问题,涉及动态规划和区间处理。第一种方法通过排序和双层循环计算,第二种方法利用rightMost数组记录水龙头的覆盖范围。
摘要由CSDN通过智能技术生成

记录一下

class Solution {
public:
    int minTaps(int n, vector<int>& ranges) {
        //先建立一个可以容纳一对数字的容器
        vector<pair<int,int>> intervals;
        //进入一个循环,填满
        for(int i = 0 ; i <= n ; i++){
            //找出头部,如果小于0,就等于0
            int start = max(0 , i - ranges[i]);
            //找出尾部,如果大于水池大小,就等于水池大小
            int end = min(n,i+ranges[i]);
            //插入
            intervals.emplace_back(start,end);
        }
        //排序一下?pair的排序方式是先头后尾
        sort(intervals.begin(),intervals.end());
        // for(int i = 0 ; i <= n ; i++){
        //     cout<<intervals[i].first<<" "<<intervals[i].second<<endl;
        // }
        //建立一个vector,有n+1个INT_MAX
        //接下来dp要放
        vector<int> dp(n+1, INT_MAX);
        dp[0] = 0;
        //进入一个循环
        for(auto[start,end]:intervals){
            //因为以及排序过了,所以如果第一个pair的第一个数不是0的话,说明不成立
            //上面的想法是错的,因为第一个位置有水龙头的话会是1
            if(dp[start] == INT_MAX)return -1;
            //再进入一个循环,起始为start,不能超过end
            for(int j = start ; j <= end ; j++){
                //在dp[j]和dp[start]+1中选一个小的赋值给dp[j]
                //这样可以把没有浇水的地方变成1
                //浇过水但是还被其它水龙头覆盖的在当前的位置上选取左边界的数+1或当前位置数(看谁是最小值)。
                dp[j] = min(dp[j],dp[start] + 1);
                // cout<<"j="<<j<<" dp[j]="<<dp[j]<<"  ";
            }
            // cout<<"\n";
        }
        return dp[n];
    }
};

另一种方法

//建立一个从零开始递增的数组,要比花园长一格,记为rightMost
//rightMost记录每一个水龙头所能触及的右边界,水龙头为0时就是不变
//因为水龙头的右边界可能是一样的,所以随着遍历的推进同一个rightMost记录的最大右边界会更新
//再进入第二个遍历
//设last记录每一个rightMost记录的最大边界,pre也记录最大边界点,但是只有i遍历到与最大边界相等时才更新一次(pre初始为0)

class Solution {
public:
    int minTaps(int n, vector<int>& ranges) {
        vector<int> rightMost(n+1);
        for(int i  = 0 ; i < n+1 ; i++){
            cout<<rightMost[i]<<endl;
        }
        //变成012345
        iota(rightMost.begin(), rightMost.end(), 0);
        //进入一个循环
        for(int i = 0 ; i < n ; i++){
            //先记录当前位置能涉及到的范围
            int start = max(0,i-ranges[i]);
            int end = min(n,i+ranges[i]);
            //记录右边界
            rightMost[start] = max(rightMost[start],end);
        }
        //last是最右边,pre是每个可用水龙头的最大右边
        int last = 0, ret =0 ,pre =0;
        //进入循环
        for(int i = 0 ; i < n ; i++){
            //记录坐标目前可见的最大右边界
            last = max(last,rightMost[i]);
            //如果last等于i,意味着当前格为0,之前的水龙头也都覆盖不到
            if(i == last){
                return -1;
            }
            //如果i == pre说明
            if(i == pre){
                ret++;
                pre = last;
            }
            cout<<"pre="<<pre<<endl;

        }
        
        return ret;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值