贪心算法 6. 跳跃游戏
难度 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

825

被折叠的 条评论
为什么被折叠?



