记录一下
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;
}
};