思路:贪心。如果我们站在i位置上,就能够往后走nums[i]步,即接下来可以到达的位置为[i+1,i+nums[i]]。那么对于这些位置,我们又可以算出可以到达他们可以到达的下一个位置,对所有的位置取一个最大值,如果最大值可以达到终点或者是终点后面,就可以保证能跳到终点。
class Solution {
public:
bool canJump(vector<int>& nums) {
int i, max_right = 0, n = nums.size();
for(i = 0; i <= max_right; ++ i){
max_right = max(max_right, i + nums[i]);
if(max_right >= n - 1){
return true;
}
}
return false;
}
};
思路:如果想要得到最少的步数,那么我们第一印象就是要让每一步走更多的步数。
A.逆向贪心
1)我们可以逆向思考,遍历一遍数组,对于所有可以到达或者超过终点的点,找到距离终点最远的那个,总步骤数+1
2)让第一步找到的离终点最远的那个点成为新的终点,重复步骤1),直到找到的新终点就是起点
class Solution {
public:
int jump(vector<int>& nums) {
int steps = 0, next_final = nums.size() - 1, i;
while(next_final){
for(i = 0; i <= next_final; ++ i){
if(i + nums[i] >= next_final){
next_final = i;
++ steps;
break;
}
}
}
return steps;
}
};
B.逆向贪心每一次都需要遍历整个数组,最差情况下真的有可能到O(n^2)。我们有没有办法正向贪心呢?也是有的
我们只要找到每一次进行跨步的点,就知道需要多少步了。那么哪些点的位置是一定要发生跨步的呢?我们假设现在我们可以选择的区间为[i,j],所有的点可以到达的最远点为right,且right不为最后一个元素,那么可以确定,在right这个点是一定要跳转的,负责就没办法继续向后走了。
也就是说,我们只需要维护这个right值,当我们踩到这个right点的时候,必须要跳转(仅限于right没有达到或者超过最终点)。
class Solution {
public:
int jump(vector<int>& nums) {
int steps = 0, n = nums.size(), i, right = 0, next_final = 0;
for(i = 0; i < n - 1; ++ i){
right = max(right, i + nums[i]);
if(i == next_final){
next_final = right;
++ steps;
}
}
return steps;
}
};