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

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



