跳跃游戏
题目描述:
解题思路:
- 第一种:贪心算法。这道题用贪心算法可以很快解决,首先我们定义
max_location
作为我们能够达到的最远距离的所需步数,我们只要能够判断这个步数大于要到达这个数组末尾的步数,就可以认为跳跃游戏成功。我们设了temp
来保存数组中每个位置能够跳跃的最大步数,当然这里容易出现一个错误,就是我们容易只顾着后面忘记了前面,我们要保证当前的位置通过之前的步数能够到达,不然后面的步数再大也是白费,例如[0,2,3]
,尽管从第二个位置能够到达末尾,但是我们从第一个位置出发无法到达第二个位置,所以这个问题的答案是错误的。这个问题解决之后,后面的就不难了,每次用max_location
保存最大步数,只要满足前面所说的条件,就返回True
。反之,返回False
。 - 时间复杂度:O(N)
class Solution:
def canJump(self, nums: List[int]) -> bool:
if len(nums) == 1:
return True
max_location = 0
for i in range(len(nums) - 1):
if max_location < i:
return False
temp = nums[i] + i
if temp > max_location:
max_location = temp
if max_location >= len(nums) - 1:
return True
return False
这里我们可以对上面的代码进行一点点优化,因为上面的代码它需要运行遍历整个数组,而我们通过分析这个题目,我们可以发现有可能一个nums
有很多种方法能够完成这个跳跃游戏,所以我们只需要求出一种情况,就可以断定这个游戏成功。那么我们就可以不需要全部遍历这个数组,只要找到一个max_location
能够满足条件,就可以返回True
了。这里我们就做了一个小改变,把判断语句放入for
循环中就可以了。虽然提交后速度跟上面差别不大,但我觉得如果数组长度变长,时间复杂度会大大降低,差别就会显现出来。
class Solution:
def canJump(self, nums: List[int]) -> bool:
if len(nums) == 1:
return True
max_location = 0
for i in range(len(nums) - 1):
if max_location < i:
return False
temp = nums[i] + i
if temp > max_location:
max_location = temp
if max_location >= len(nums) - 1:
return True
return False
- 第二种:反向查找。这里我们可以逆向思维,从数组尾部往头部来查找,这也是一种新思路,我们首先定义起始位置
location
,然后反向遍历数组,如果说location
位置能被第i
位数字所获取,则我们就将location
往前挪到第i
个位置,直到最后遍历结束,如果说这个location
到达数组的第一位置,说明这个跳跃游戏成功。 - 时间复杂度:O(N)
class Solution:
def canJump(self, nums: List[int]) -> bool:
location = len(nums) - 1
for i in range(len(nums) - 2, -1, -1):
if location - i <= nums[i]:
location = i
return location == 0
- 第三种:动态规划。通过看了别人的方法,我觉得动态规划也是一个很好的方法来解决这种问题。我们用
dp
数组存第i
个点能跳最远的位置,然后判断第i
个点是可以到的。 - 时间复杂度:O(N)
class Solution:
def canJump(self, nums: List[int]) -> bool:
if len(nums) == 1:
return True
dp = [0 for i in range(len(nums))]
dp[0] = nums[0]
for i in range(1, len(nums)):
if dp[i - 1] >= i:
dp[i] = max(i+nums[i], dp[i-1])
else:
dp[i] = 0
if dp[len(nums) - 1] >= len(nums)-1:
return True
else:
return False