Cover image for 面试经典150题 P45 跳跃游戏II

面试经典150题 P45 跳跃游戏II


时间轴

时间轴

2025-10-02

init

贪心,动态规划

题目:

我最先想到的是动态规划令 dp[i] 表示到达 i 的最小跳跃次数,-1 表示不可达,那么对于 0 <= j < i,如果 j 可以到达 i ,即 nums[j] + j >= i 且 dp[j] != -1

dp[i]=min(dp[j]+1) dp[i] = min (dp[j] +1)

如果没有可达的 j 那么

dp[i]=1 dp[i] = -1

123456789101112131415161718192021222324252627282930313233
#include <climits>#include <vector>using std::vector;class Solution {public:  int jump(vector<int> &nums) {    // dp[i]表示到达i的最小跳跃次数,-1表示不可达    // 对于 0<=j <i    // if(nums[j] + j >= i ) dp[i] = dp[j] + 1;    // 如果不存在这样的j,dp[i] = -1;    int n;    int min;    n = nums.size();    vector<int> dp(n, -1);    dp[0] = 0;    for (int i = 1; i < n; i++) {      min = INT_MAX;      for (int j = 0; j < i; j++) {        if (nums[j] + j >= i && dp[j] != -1 && dp[j] + 1 < min) {          min = dp[j] + 1;        }      }      if (min != INT_MAX) {        dp[i] = min;      } else {        dp[i] = -1;      }    }    return dp[n - 1];  }};

这道题其实是经典的贪心题,从后往前看,最后一个位置一定是之前某个位置跳过来的,但是这个之前的位置可能有多个,那么我们就贪心地选择最远的那个(因为反正都是多一步,选择离起点更近的必定能减少跳跃次数,这因为如果两个点都能到达最后一个位置,a 的位置靠前,b 的位置靠后,那么我们肯定会选择 a,因为到达 a 的 step 必定小于等于 b 的 step)。选择后,选择的这个位置就成了新的最后一个位置。

123456789101112131415161718
class Solution {public:    int jump(vector<int>& nums) {        int position = nums.size() - 1;        int steps = 0;        while (position > 0) {            for (int i = 0; i < position; i++) {                if (i + nums[i] >= position) {                    position = i;                    steps++;                    break;                }            }        }        return steps;    }};

也可以用下面这道题的思路改造

官方题解:

如果我们「贪心」地进行正向查找,每次找到可到达的最远位置,就可以在线性时间内得到最少的跳跃次数。

例如,对于数组 [2,3,1,2,4,2,3],初始位置是下标 0,从下标 0 出发,最远可到达下标 2。下标 0 可到达的位置中,下标 1 的值是 3,从下标 1 出发可以达到更远的位置,因此第一步到达下标 1。

从下标 1 出发,最远可到达下标 4。下标 1 可到达的位置中,下标 4 的值是 4 ,从下标 4 出发可以达到更远的位置,因此第二步到达下标 4。

fig1
fig1

在具体的实现中,我们维护当前能够到达的最大下标位置,记为边界。我们从左到右遍历数组,到达边界时,更新边界并将跳跃次数增加 1。

在遍历数组时,我们不访问最后一个元素,这是因为在访问最后一个元素之前,我们的边界一定大于等于最后一个位置,否则就无法跳到最后一个位置了。如果访问最后一个元素,在边界正好为最后一个位置的情况下,我们会增加一次「不必要的跳跃次数」,因此我们不必访问最后一个元素。

123456789101112131415161718192021
class Solution {public:    int jump(vector<int>& nums) {        int i = 0, j = 0, n = nums.size();        int max_pos = 0;        int last_end = 0;        int step = -1;        for(i = 0; i< n;i++){            max_pos = std::max(max_pos, i + nums[i]);            if(i == last_end){                last_end = max_pos > n-1 ? n-1: max_pos;                step++;            }        }        return step;    }};

leetcode hot 100 rewrite

1234567891011121314151617181920212223242526
#include <vector>using std::vector;class Solution {    public:        int jump(vector<int> &nums)        {                // 从后往前跳,贪心地选择最远的那个能跳过来的                int i, n = nums.size();                int curr = n - 1;                int cnt = 0;                while (curr > 0) {                        for (i = 0; i < curr; i++) {                                if (nums[i] + i >= curr){                                        curr = i;                                        cnt++;                                        break;                                }                        }                }                return cnt;        }};
评论加载中…