55. 跳跃游戏
文章目录
- 【每日力扣】力扣55. 跳跃游戏
- 题目描述
- 输入输出示例
- 示例 1
- 示例 2
- 思路分析
- 代码实现
- 复杂度分析
- 总结
【每日力扣】力扣55. 跳跃游戏
博主写这篇文章的时候已经凌晨1点30分啦。故想分享一下中医的子午觉这一养生技巧,就算真的要熬夜,也最好在23点~1点的时候睡一觉。
题目描述
给定一个非负整数数组 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
和位置2
,它们的数字分别为10和20,
如果去位置1
,我们就必定可以到达[1, 1 + 10]
这个区间的任一位置
如果去位置2
,我们就必定可以到达[2, 2 + 20]
这个区间的任一位置
所以,
如果我们希望尽可能找到一条能到达最后一个位置的路,显然我们只需要一直沿着最高“价值”的路径就可以了。这样,这道题就转换成了一个翻版贪心捡钱的问题(捡100块比10块好),道理都是一样的。
具体思路如下:
- 初始化
max_reach
为 0,表示当前能到达的最远位置。 - 遍历数组中的每一个元素,判断当前下标
i
是否在max_reach
范围内,如果不在,则说明无法到达当前位置,返回false
。 - 如果在
max_reach
范围内,则更新max_reach
为i + nums[i]
和当前max_reach
的最大值。 - 如果在遍历过程中,
max_reach
大于等于数组的最后一个下标,返回true
。
代码实现
class Solution:
def canJump(self, nums: List[int]) -> bool:
# max_reach 表示当前能到达的最远位置
max_reach = 0
for i in range(len(nums)):
# 如果当前下标 i 超过了 max_reach,说明无法到达当前位置
if i > max_reach:
return False
# 更新 max_reach
max_reach = max(max_reach, i + nums[i])
# 如果 max_reach 已经超过或到达最后一个下标,则返回 True
if max_reach >= len(nums) - 1:
return True
return False
复杂度分析
- 时间复杂度:
O
(
n
)
O(n)
O(n),其中
n
n
n 是数组
nums
的长度。我们只需要遍历一次数组即可完成所有的判断和计算。 - 空间复杂度:
O
(
1
)
O(1)
O(1),我们只使用了常数个额外空间来存储变量
max_reach
。
总结
本题使用贪心算法解决,通过维护一个能到达的最远位置来判断是否可以到达最后一个位置。贪心算法的核心思想在于每一步都做出局部最优选择,即选择能到达的最远位置,从而保证最终可以达到全局最优。通过这种方式,我们能够在 O ( n ) O(n) O(n) 的时间复杂度内判断是否可以跳跃到最后一个位置。
这道题目的核心思路和贪心算法的思想高度一致,通过每一步选择最佳方案来确保最终的整体最优。希望这篇文章能够帮助你更好地理解贪心算法在实际问题中的应用。