【跳跃游戏】——贪心算法

55. 跳跃游戏

一、题目难度

中等

三、题目描述

给你一个非负整数数组 nums,你最初位于数组的第一个下标。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true;否则,返回 false

四、示例

示例1

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

示例2

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

五、提示

  1. 1 <= nums.length <= 104
  2. 0 <= nums[i] <= 105

贪心算法

  1. 整体目标:
    • 判断从数组的第一个下标出发,能否通过按照数组中每个位置所规定的最大跳跃长度进行跳跃,最终到达最后一个下标。
  2. 贪心策略:
    • 在每一个位置,我们不需要去考虑所有可能的跳跃路径,而是只关注当前位置能够跳到的最远位置furthest
    • 对于当前位置i,我们可以计算出它能跳到的最远位置为 i + nums[i]
    • 不断更新最远距离furthest
    • 判断是否到达终点
  3. 贪心策略判断:
    • 如果遍历过程中,遍历到某位置i时,i超越了能跳到的最远位置furthest。说明无法继续前进,不可能到达末尾
    • 如果遍历整个数组,一直没出现以上情况,说明可以到达末尾!

代码实现

根据以上思路很容易写出代码:

python 复制代码
class Solution:
    def canJump(self, nums: List[int]) -> bool:
        # 贪心算法?
        furthest = 0 # 初始化最远距离
        # 从头开始遍历i
        for i in range(len(nums)):
            furthest = max(i + nums[i], furthest)
            if i > furthest:
                return False
        return True
------------------------------------------------------------------------------------------------------------
解答错误
107 / 173 个通过的测试用例

官方题解
输入
nums =
[3,2,1,0,4]

添加到测试用例
输出
true
预期结果
false

哪里出了问题?

思考:

python 复制代码
if i > furthest:
                return False

实际上,应该加上>=

python 复制代码
解答错误
152 / 173 个通过的测试用例

官方题解
输入
nums =
[0]

添加到测试用例
输出
false
预期结果
true

忘记考虑空集了!

python 复制代码
class Solution:
    def canJump(self, nums: List[int]) -> bool:
        # 贪心算法?
        if not nums:return False
        furthest = nums[0] # 初始化最远距离
        # 从头开始遍历i
        for i in range(len(nums)):
            furthest = max(i + nums[i], furthest)
            if i >= furthest:
                return False
        return True
------------------------------------------------------------------------------------------------------------------------------------------------
解答错误
152 / 173 个通过的测试用例

官方题解
输入
nums =
[0]

添加到测试用例
输出
false
预期结果
true

通过用例完全没加...

正确答案:

python 复制代码
def canJump(nums):
    n = len(nums)
    furthest = 0

    for i in range(n):
        if i > furthest:
            return False
        furthest = max(furthest, i + nums[i])

    return True

这几个疑问:

疑问一:为什么先判断 if i > furthest: 再执行 furthest = max(furthest, i + nums[i])

在使用贪心算法解决"跳跃游戏"问题的这段代码中,furthest 变量用于记录从起始位置能够到达的最远位置。

  • 先判断能否继续前进 :当我们遍历数组 nums 时,在每一个位置 i,我们首先需要判断当前位置是否已经超出了之前所能到达的最远位置(即 i > furthest)。如果已经超出了,那就意味着按照之前的跳跃规则,我们无法到达当前位置 i,更不可能到达数组的最后一个下标了,所以此时应该直接返回 False,表示无法完成跳跃到达最后一个下标。

  • 更新最远可到达位置 :只有当当前位置 i 没有超出之前记录的最远位置 furthest 时,我们才继续更新 furthest 的值。通过 furthest = max(furthest, i + nums[i]),我们将当前位置 i 加上它能跳跃的最大长度 nums[i] 得到的新的可能到达的最远位置,与之前记录的最远位置 furthest 进行比较,取两者中的最大值作为新的 furthest。这样就能不断更新我们能够到达的最远位置信息,以便后续继续判断是否能到达最后一个下标。

如果先更新 furthest 再判断 i > furthest,就可能会出现一种情况:在更新 furthest 之后,当前位置 i 实际上已经是无法到达的了(因为是基于之前错误地认为能到达而更新的 furthest),但却没有及时发现并返回 False,导致后续的计算出现错误,最终得到错误的结果。所以必须先判断能否继续前进,再更新最远可到达位置。

疑问二:为什么 if i > furthest: 没有等于号=

这里不包含等于号是因为当 i == furthest 时,我们仍然有可能从当前位置继续跳跃到达更远的地方。

假设当前位置 i 刚好等于之前记录的最远位置 furthest,这意味着我们刚好到达了之前所能到达的最远距离,但此时我们还可以根据当前位置 i 对应的元素 nums[i] 所表示的跳跃长度进行跳跃,有可能跳到更远的位置,所以此时不能判定为无法到达后续位置,不能返回 False

只有当 i 严格大于 furthest 时,才说明我们已经无法按照之前的跳跃规则到达当前位置 i 了,也就不可能到达最后一个下标,此时才返回 False

疑问三:为什么不用写特解情况,比如 nums 为空或者只有一个元素等!

  • 对于空数组情况 :在Python中,如果直接对空数组执行 for i in range(n)(其中 n 是数组长度)这样的操作,实际上循环体不会被执行。因为空数组的长度为 0range(0) 会生成一个空的可迭代对象,所以循环内的代码不会被执行到。而在这种情况下,由于没有进行任何有效的跳跃操作,默认就可以认为是无法到达最后一个下标(因为根本就没有下标可供到达),所以最终函数会返回一个默认值(在Python中函数如果没有显式返回值,默认返回 None,这里由于代码结构,实际上返回值应该是根据循环执行情况确定的,循环未执行就相当于返回了 False 的效果),这与我们期望的空数组时返回 False 的结果是相符的。

  • 对于只有一个元素的数组情况 :当数组只有一个元素时,我们最初位于数组的第一个下标(也就是唯一的这个下标),此时不需要进行任何跳跃就已经到达了"最后一个下标"(因为只有一个下标)。在代码中,当进入循环时,i 的值为 0,此时 furthest 初始值为 0(假设没有在循环外对其进行额外赋值),那么 i == furthest,根据前面的分析,这种情况不会返回 False,而是会继续执行 furthest = max(furthest, i + nums[i]),更新后的 furthest 依然为 0(因为 nums[0] 加上 0 还是 0),然后循环结束,最终函数会返回 True,这也符合我们对于只有一个元素的数组能到达最后一个下标(其实就是它本身)的预期结果。

所以在这段代码的逻辑下,不需要额外针对 nums 为空或者只有一个元素等特殊情况单独编写处理代码,代码本身的执行逻辑已经能够正确处理这些特殊情况并得到符合预期的结果。

相关推荐
xiaoshiguang34 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡4 小时前
【C语言】判断回文
c语言·学习·算法
别NULL4 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇4 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
yuanbenshidiaos5 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习5 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA6 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo6 小时前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
jackiendsc6 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
游是水里的游7 小时前
【算法day20】回溯:子集与全排列问题
算法