45 跳跃游戏II【python3】

文章讨论了一种跳跃游戏问题,通过递归方法解决时遇到超时问题,然后转向使用动态规划进行优化,减少计算量。进一步的优化是限制循环中的搜索范围,提高效率。最终,通过采用贪心策略,从终点反向查找最小跳跃路径,实现了109/109用例的通过。

穷举/递归-通过率73/109

用递归的方式求出所有可能的跳跃路径,找出路径最短的那个。
用例通过73/109,递归太多了会超时

class Solution:
    def jump(self, nums: List[int]) -> int:

        res=[] # 记录从0到n-1的跳跃次数
        
        # W是当前跳跃路径
        def f(W):
            # 到达nums[n-1]结束递归
            if W[-1]== len(nums)-1:
                #print(W)
                res.append(len(W)-1)
                return 'finish'
            # 否则继续跳跃
            i=W[-1]
            k=(i+nums[i]+1 if i+nums[i]+1<len(nums) else len(nums) )
            for j in range(i+1,k):
                tmp=W[:]
                tmp.append(j)
                f(tmp)
                  

        f([0])
        
        return min(res)

动态规划-通过率101/109

用dp[i]记录从位置0跳跃到位置i的最小跳跃次数。dp的初始化显然跟nums[0]有关,对于位置k(1<=k<=nums[0]),dp[k]=1.
因此之后从位置nums[0]+1开始更新dp[i]即可,对于1<=j<=num[0],只要j+nums[j]>=i,就可以跳跃。而dp[i]=min(dp[j])+1
dp[n-1]即为所求。
其中还需要处理的两种特殊情况:n=1时;从位置0可以直接跳跃到n-1时.
用例101/109,两层循环,最后面n超大的时候会超时。

class Solution:
    def jump(self, nums: List[int]) -> int:
        n=len(nums)
        # 特殊情况的处理
        if n==1:
            return 0
        if n>=2:
            # dp[i]记录跳到位置i的最小次数
            dp=[0]*n
            # 初始化dp:从位置1到nums[0]的最小跳跃次数都为1
            # 如果初始化的时候即可跳到n-1,则返回最小跳跃次数1
            for i in range(1,min(nums[0]+1,n)):
                dp[i]=1
            if dp[n-1]>0:
                return 1
            # 若不能一次跳到位置n-1:
            # 从位置nums[0]+1开始更新dp[i],对于1<=j<=num[0],只要j+nums[j]>=i,就可以跳跃
            for i in range(nums[0]+1,n):
                res=[]
                for j in range(1,i):
                    if j+nums[j]>=i:
                        res.append(dp[j])
                dp[i]=min(res)+1
            return dp[n-1]

优化-用例通过104/109

从位置0跳到位置j,应该是越小的j,需要的跳跃次数就可能越小。故对于“从位置nums[0]+1开始更新dp[i],对于1<=j<=num[0],只要j+nums[j]>=i,就可以跳跃”这个步骤的j而言,可以在第一个j就停止循环,更新dp[i]。
此时后面的超长用例可以多通过3个

# 若不能一次跳到位置n-1:
            # 从位置nums[0]+1开始更新dp[i],对于1<=j<=num[0],只要j+nums[j]>=i,就可以跳跃
            for i in range(nums[0]+1,n):
                res=[]
                for j in range(1,i):
                    if j+nums[j]>=i:
                        dp[i]=dp[j]+1
                        break # 第一个可以跳跃的地方跳跃次数最短

贪心+反向查找-用例通过109/109

从终点位置n-1反向查找,每一步找到可跳跃到当前位置最小的点,直到跳回位置0

class Solution:
    def jump(self, nums: List[int]) -> int:
        n=len(nums)
        # 处理特殊情况
        if n==1: 
            return 0
        number=0 # 记录跳跃次数
        # 反向查找,每一步找到离当前最远的可跳跃的点,直到跳回位置0
        cur_node=n-1
        number=0
        while 1:
            for i in range(cur_node):
                if nums[i]+i>=cur_node:
                    cur_node=i
                    number+=1
                    break
            if cur_node==0:
                break
            
        
        return number
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值