贪心算法 6. 跳跃游戏

贪心算法 6. 跳跃游戏

55. 跳跃游戏 - 力扣(LeetCode)

代码随想录

难度 5 - 中等

  • 要点:

    依然是参考代码随想录,贪心算法没有定式,一下子真有点难想。

    刚看到本题一开始可能想:当前位置元素如果是 3,我究竟是跳一步呢,还是两步呢,还是三步呢,究竟跳几步才是最优呢?

    其实跳几步无所谓,关键在于可跳的覆盖范围!

    不一定非要明确一次究竟跳几步,每次取最大的跳跃步数,这个就是可以跳跃的覆盖范围。

    这个范围内,别管是怎么跳的,反正一定可以跳过来。

    那么这个问题就转化为跳跃覆盖范围究竟可不可以覆盖到终点!

    每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围。

    贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点

    局部最优推出全局最优,找不出反例,试试贪心!

    可以参考图像

    i 每次移动只能在 cover 的范围内移动,每移动一个元素,cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。

    而 cover 每次只取 max(该元素数值补充后的范围, cover 本身范围)。

    如果 cover 大于等于了终点下标,直接 return true 就可以了。

    注意,我们需要维护的实际上是一个跳跃覆盖范围!这才是解出本道题的关键。

  • 代码:

    class Solution:
        def canJump(self, nums):
            if len(nums) == 1:
                return True
    
            i = 0 # 指向当前元素
            max_range_idx = 0 # 存储当前最大范围的最右侧元素下标(最右侧元素包含在范围中)
            while i <= max_range_idx: # 当i在最大可跳转范围内时
                if max_range_idx >= len(nums) - 1: # 如果最大范围覆盖到了末尾元素,则成功跳转
                    return True
    
                if i + nums[i] > max_range_idx: # 更新最大范围
                    max_range_idx = i + nums[i]
    
                i += 1 # 更新i
    
            # 遍历结束没有成功跳转,则返回False
            return False
    
  • 时间复杂度: O(n)

  • 空间复杂度: O(1)

  • 简化写法:

    class Solution:
        def canJump(self, nums: List[int]) -> bool:
            cover = 0
            if len(nums) == 1: return True
            for i in range(len(nums)):
                if i <= cover:
                    cover = max(i + nums[i], cover)
                    if cover >= len(nums) - 1: return True
            return False
    
  • 另一种思路:

    ## 基于当前最远可到达位置判断
    class Solution:
        def canJump(self, nums: List[int]) -> bool:
            far = nums[0]
            for i in range(len(nums)):
                # 要考虑两个情况
                # 1. i <= far - 表示 当前位置i 可以到达
                # 2. i > far - 表示 当前位置i 无法到达
                if i > far:
                    return False
                far = max(far, nums[i]+i)
            # 如果循环正常结束,表示最后一个位置也可以到达,否则会在中途直接退出
            # 关键点在于,要想明白其实列表中的每个位置都是需要验证能否到达的
            return True
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值