力扣 每日一题 1326. 灌溉花园的最少水龙头数目【难度:困难,rating: 1885】(动态规划)

题目链接

https://leetcode.cn/problems/minimum-number-of-taps-to-open-to-water-a-garden/

题目来源于:第172场周赛 Q4 rating: 1885

思路

得到所有区间,按左端点L、右端点R进行排序。然后遍历这些区间覆盖的每个点i,保证L<=i<=R,设dp[i]是覆盖[0,i]的线段最小个数,则有状态转移方程 d p [ i ] = m i n ( d p [ i ] , d p [ L ] + 1 ) dp[i]=min(dp[i],dp[L]+1) dp[i]=min(dp[i],dp[L]+1)
初始化dp=inf表示不可到达,遍历排序的区间保证 i 位置能从前一个 L 位置正确转移,如果发现dp[L]=inf则说明无法转移(接不上前面区间有断层)直接返回-1。

代码

class Solution {
    static const int N=10110,inf=0x3f3f3f3f;
    int dp[N]; // 覆盖[0,i]的线段最小个数
    vector<pair<int,int>> segments; // 线段
public:
    int minTaps(int n, vector<int>& ranges) {
        for(int i=0;i<ranges.size();i++){
            if(ranges[i]==0)continue; // 单个点无用
            int x=max(0,i-ranges[i]);
            int y=min(n,i+ranges[i]);
            segments.push_back(make_pair(x,y));
        }
        sort(segments.begin(),segments.end());
        memset(dp,inf,sizeof(dp));
        dp[0]=0; // 注意初始化坐标0!
        for(auto &[l,r]:segments){ // 每次加一个区间进来
            for(int i=l;i<=r;i++){ // 遍历更新这个区间内的所有dp值
                if(dp[l]==inf){
                    return -1;
                }
                dp[i]=min(dp[i],dp[l]+1);
            }
        }
        return dp[n]==inf?-1:dp[n];
    }
};
/*
7
[1,2,1,0,2,1,0,1]
ans: 3
*/

你可能感兴趣的:(力扣-剑指offer,leetcode,动态规划,算法)