Skip to content

题目链接 · 灵神原题解(署名来源)

题意:从 i 可以跳到闭区间 [i,i+numsi] 中的任意整数。问:能不能从 0 跳到 n1

先看示例 2,nums=[3,2,1,0,4]。我们在遍历数组的同时,维护最右可以到达的位置 mx,如下表:

inumsii+numsimx
0333
1233
2133
3033
448失败

0 可以跳到 1,2,3,但是无法从 1,2,3 中的任何位置跳到 4。当我们遍历到 i=4 时,发现

i>mx

这意味着 i 是无法到达的,返回 false

然后来看示例 1,nums=[2,3,1,1,4],在遍历数组的同时,维护最远可以到达的位置 mx,如下表:

inumsii+numsimx
0222
1344
2134
3144
4488

0 可以跳到 1,2,最远可以到达的位置 mx=2。能否跳到更远的位置?那就看从 1 能跳到哪些位置,从 2 能跳到哪些位置。

1 可以跳到 2,3,4mx 更新成 4

2 可以跳到 3mx 不变。

3 可以跳到 4mx 不变。

到达 4,返回 true

一般地,算法如下:

  1. 从左到右遍历 nums,同时维护能跳到的最远位置 mx,初始值为 0
  2. 如果 i>mx,说明无法跳到 i,返回 false
  3. 否则,用 i+numsi 更新 mx 的最大值。
  4. 如果循环中没有返回 false,那么最后返回 true

另一种理解方式是,把每个 numsi 看成闭区间 [i,i+numsi],问题变成判定这 n 个区间能否合并成一个大区间(而不是多个区间),这可以用 56. 合并区间算法 解决。

python
class Solution:
    def canJump(self, nums: List[int]) -> bool:
        mx = 0
        for i, jump in enumerate(nums):
            if i > mx:  # 无法到达 i
                return False
            mx = max(mx, i + jump)  # 从 i 最右可以跳到 i+jump
        return True
cpp
// C++ 版待补充
cpp
class Solution {
public:
    bool canJump(vector<int>& nums) {
        int mx = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (i > mx) { // 无法到达 i
                return false;
            }
            mx = max(mx, i + nums[i]); // 从 i 最右可以跳到 i + nums[i]
        }
        return true;
    }
};

也可以在 mxn1 时就返回 true,这可以让我们提前退出循环。

python
class Solution:
    def canJump(self, nums: List[int]) -> bool:
        mx = 0
        for i, jump in enumerate(nums):
            if i > mx:  # 无法到达 i
                return False
            mx = max(mx, i + jump)  # 从 i 最右可以跳到 i + jump
            if mx >= len(nums) - 1:  # 可以跳到 n-1
                return True
cpp
// C++ 版待补充
cpp
class Solution {
public:
    bool canJump(vector<int>& nums) {
        int mx = 0;
        for (int i = 0; mx < nums.size() - 1; i++) {
            if (i > mx) { // 无法到达 i
                return false;
            }
            mx = max(mx, i + nums[i]); // 从 i 最右可以跳到 i + nums[i]
        }
        return true;
    }
};

复杂度分析

  • 时间复杂度:O(n),其中 nnums 的长度。
  • 空间复杂度:O(1)

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

本文整理自灵茶山艾府(endlesscheng)的公开内容,仅供个人学习使用

本站仅供个人学习使用,请勿外传