前言
感觉开始打cf了以后贪心的能力有了明显的提升,让我们谢谢cf的感觉场。
一、跳跃游戏 II
class Solution {
public:
int jump(vector<int>& nums) {
int n=nums.size();
//怎么感觉这个题也在洛谷上刷过(?)
int cur=0;//当前步最远位置
int next=0;//多跳一步最远位置
int ans=0;
for(int i=0;i<n;i++)
{
//到不了i位置 -> 跳
if(cur<i)
{
ans++;
cur=next;
}
next=max(next,i+nums[i]);
}
return ans;
}
};
真感觉这个题在洛谷上刷到过类似的。
这类问题就是设置一个当前步数内能到的最远距离和再多跳一步能到的最远距离。然后只要当前步数内跳不到了,就增加步数继续跳,每次看从当前位置能否把next更新得更大即可。
这个说白了就是动态规划的思想。
二、灌溉花园的最少水龙头数目
class Solution {
public:
int minTaps(int n, vector<int>& ranges) {
//right[i]:从左侧最远i到右侧最远的位置j
vector<int>right(n+1);
for(int i=0;i<=n;i++)
{
int left=max(0,i-ranges[i]);
right[left]=max(right[left],i+ranges[i]);
}
int cur=0;//当前数量的水龙头最右影响的位置
int next=0;//多打开一个的最右位置
int ans=0;
for(int i=0;i<n;i++)
{
//开能从i往右覆盖最远的水龙头
next=max(next,right[i]);
if(i==cur)//来到最右边界
{
if(next>i)//后续能覆盖
{
cur=next;
ans++;
}
else
{
return -1;
}
}
}
return ans;
}
};
这个题要注意的是,单点满足是不符合题意的,必须要区间覆盖才行。
整体思路是首先构建一个right数组,含义是从i位置开始能覆盖到的最右位置,然后就把这道题转化成了上一道题。
具体就是每次先找出每个水龙头能覆盖到的最左位置,然后就能去看这个水龙头能不能把这个最左位置的right更新得更远。之后就是和上个题一样设置cur和next两变量,不一样的是,每次先更新next,然后直到此时来到了最右边界,才去看是否再开一个能覆盖后续。如果能覆盖,即next大于i,那就多开一个,否则说明当前水龙头到下一个水龙头中间的位置是覆盖不到的,那就直接返回-1即可。
三、过河问题
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
/*
这题让我想到了小时候玩的一个游戏
两个策略:
1.让最小的人一趟一趟送
2.让最小的两个人先过去,然后其中一人把船开回来,
再让最大的两个人过去,再让另一个人回来
*/
void solve()
{
int n;
cin>>n;
vector<int>a(n);