题目

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

提示:

  • 1 <= nums.length <= 3 * 104
  • 0 <= nums[i] <= 105

解答

  1. 利用栈(超时

将能到达的数组元素推进栈,模拟树的操作,但是会超时。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int len = nums.size();
        if (len > 1 && nums[0] == 0) return false;
        if (len == 1) return true;
        stack<int> s; // 定义一个栈
        int index = 0;
        if (nums[index] > len) return true;
        s.push(index);
        while(!s.empty()) {
            int temp_index = s.top();
            int temp_num = nums[temp_index];
            s.pop();
            for (int i = 1; i <= temp_num; i++) {
                if (temp_index + i == len - 1) return true;
                if (nums[temp_index + i] >= (len - (temp_index + i))) return true;
                if (nums[temp_index + i] != 0) s.push(temp_index + i);
            }
        }
        return false;
    }
};

用chatGPT分析超时的原因:

您的代码的时间复杂度为 O(2^n),其中 n 是数组的长度,因为在每个位置都可以有两个选择:跳或不跳,总共有 2^n 种可能的路径。这样的时间复杂度是无法通过本题的。

此外,您使用了栈来存储待搜索的位置,但这样的做法并不高效。因为每个位置最多只需要被遍历一次,而使用栈会重复遍历一些位置,导致时间复杂度进一步增加。

  1. 使用贪心算法

使用贪心算法,从左到右遍历数组,用一个变量来维护能够到达的最远距离,如果当前位置在这个最远距离之内,那么更新最远距离。如果遍历结束后最远距离大于等于数组的最后一个位置,那么就说明可以到达最后一个位置,否则就无法到达。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n = nums.size();
        int maxPos = 0; // 当前能到达的最远距离
        for (int i = 0; i < n; i++) {
            if (i > maxPos) return false; // 如果当前位置无法到达,则返回false
            maxPos = max(maxPos, i + nums[i]); // 更新能够到达的最远距离
            if (maxPos >= n - 1) return true; // 如果能够到达最后一个位置,返回true
        }
        return false;
    }
};