题目描述
回溯法
第一种比较容易想到的解法是:穷举从第一个位置跳到最后一个位置的所有可能方案。具体来说,从第一个位置开始,根据当前位置上的数值知道了在该位置上可以跳跃的最大长度,在(1~可跳跃最大长度)这个范围内枚举所有可以跳到的位置,每次选取一个跳跃长度并跳到下一个新的位置后,重复上述操作,当遇到当前位置上的数值为0,没有办法继续跳的时候,就回溯。
class Solution(object):
def canJumpFromPosition(self, p, nums):
if p == len(nums)-1: # 可以跳到最后一个位置上
return True
furthestCanJump = min(p+nums[p], len(nums)-1) #记录当前位置可以跳跃到的最远位置
for nextP in range(p+1, furthestCanJump+1): #枚举当前位置可以跳到的所有位置
if self.canJumpFromPosition(nextP, nums): #每次跳到一个新的位置后,重复上述操作
return True
return False
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
return self.canJumpFromPosition(0, nums)
这是一个低效的解决方法,时间复杂度比较高,提交后超出时间限制。
一种改进思路是,从大到小遍历跳跃长度,即每次选择最大的步数开始去跳跃,直觉上这样可以更快跳到最后一个位置。
'''
range(start,end,step)
1.start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
2.stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
3.step:步长,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)
for循环实现倒序遍历:
range(7,1,-1):start = 7, end = 1, step =-1, 跟正序一样不包括end,即不包括1,输出为[7, 6, 5, 4, 3, 2]
'''
class Solution(object):
def canJumpFromPosition(self, p, nums):
if p == len(nums)-1:
return True
furthestCanJump = min(p+nums[p], len(nums)-1)
for nextP in range(furthestCanJump, p, -1): # 从大到小遍历跳跃长度,即每次选择最大的步数开始去跳跃
if self.canJumpFromPosition(nextP, nums):
return True
return False
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
return self.canJumpFromPosition(0, nums)
提交后还是超时了,说明递归回溯的方法确实时间复杂度太高了。。。
动态规划
设置一个flag,表示能否跳到当前节点。
- 如果跳不到某个位置 i,那么一定跳不到 i 后面所有的位置。
- 如果可以跳到某个位置 i,则一定可以跳到 i 前面的任意一个位置上。
在遍历到最后一个位置之前,如果存在任意一个位置跳不到,那么就肯定到达不了最后一个位置,直接return False。
class Solution:
def canJump(self, nums):
flag = False
for i in range(1, len(nums)):
flag = False # 每遍历到一个新的位置时,flag初始化为False
for j in range(i-1,-1,-1): #在求解第 i个位置的flags时,向前遍历
if (nums[j] + j >= i): #如果存在某个位置 j 能跳到 i,那么 i 的flags就为True。
flag = True
break
if not flag: #如果存在任意一个位置跳不到,那么就肯定到达不了最后一个位置,直接return False。
return False
return True # 到达最后一个位置上
时间复杂度:最好O(n),最差O(n2),平均O(n2)
空间复杂度: O(1)
贪心算法
实际上这个题目用贪心思想是最快的,一次循环遍历即可求解。实际上对这个题目来说,有一个重要的条件是:如果当前位置能跳到某个位置 index,那么当前位置也一定能跳到 index 之前的所有位置。因此,每次只要尽可能跳到最远的位置,然后遍历数组,不断更新能到达的最远位置,比较最远位置和最后一个位置即可。
class Solution(object):
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
max_dist = 0 #初始化当前能到达的最远位置
for i, jump in enumerate(nums): # i为当前位置,jump是当前位置的最大跳跃长度
if max_dist >= len(nums)-1: # 判断当前能到达的最远位置是否能到达最后一个位置
return True
if max_dist>=i and i+jump>max_dist: # 如果当前位置可达,并且当前位置+跳数>最远位置
max_dist = i+jump # 更新最远能到达的位置
return False
时间复杂度O(n),空间复杂度O(1)。
最后,如果大家有更好的Python解法,欢迎在评论区分享下您的解法,一起进步,感谢^ o ^~