【Python实战】LeetCode55:跳跃游戏

题目描述

在这里插入图片描述

回溯法

第一种比较容易想到的解法是:穷举从第一个位置跳到最后一个位置的所有可能方案。具体来说,从第一个位置开始,根据当前位置上的数值知道了在该位置上可以跳跃的最大长度,在(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 ^~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值