携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
题目
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例 1
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/jump-game
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
提示
- 1 <= nums.length <= 3 * 10^4
- 0 <= nums[i] <= 10^5
题解
思路
我们知道,在贪心问题中,如果想要将某个区间完全覆盖(并且要使得覆盖中所用到的区间数最少,本题未涉及区间数最少) 我们的思路是对左端点从小到大进行排序,然后对于区间 [st,ed] 而言,我们从左往右遍历排序后的区间,找到左端点 <=st 且右端点最大的这个区间 则覆盖了 [st,r] 这一部分的区间,然后再对剩下的区间 [r,ed] 进行覆盖 如果最终 r>=ed 则说明覆盖成功 如果 r<st 则一定有 [st,r] 的这一部分未被覆盖,说明覆盖失败。
本题中 我们如何将问题转换为区间覆盖问题 例如 num=[2,3,1,1,4] 要想从第一个位置跳到最后一个位置,可以等价于覆盖 [0,4] 这个区间 num[0]=2 第一个区间为[0,2] num[1]=3 第二个区间为[1,4] num[2]=1 第三个区间为[2,3] num[3]=1 第四个区间为[3,4]
那么显然只需要前两个区间即可覆盖整个区间,因此返回 true 在 C++ 中我们使用 pair<int,int> 来存放区间的左右端点,由于整个区间一定是以左端点从小到大排序,因此就不需要我们使用 sort 函数进行排序了 这个代码有一个好处就是,如果需要计算最少需要跳跃几次可以到达重点,只需要在循环加入一个变量 res,然后每次更新区间的时候 res++,最后返回 res 即可。
代码
class Solution {
public:
bool canJump(vector<int>& nums) {
//区间覆盖问题
if(nums.size()==1)
return true;
typedef pair<int,int>PII;
vector<PII>v;
for(int i=0;i<nums.size()-1;i++)
v.push_back({i,i+nums[i]});//存储从0到i-1个区间的范围
//由于已近按照左端点从小到大排序 因此不需要排序
int st=0,ed=nums.size()-1;
// 判断v中的区间是否能够覆盖[st,ed]区间
for(int i=0;i<v.size();i++) {
int j=i,r=-2e9;
while(j<v.size()&&v[j].first<=st) //找到第一个左端点在st区间的左侧且右端点最大的点
{
r=max(r,v[j].second);
j++;
}
if(r<st)
break;
if(r>=ed)
return true;
st=r; //已经覆盖完[st,r]区间 接下来覆盖剩下的区间[r,ed]即可
i=j-1; //循环结束i会自增1 因此等于j-1
}
return false;
}
};
结语
业精于勤,荒于嬉;行成于思,毁于随。