Leetcode 45:跳跃游戏 II(最详细的解法!!!)

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/83109778

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

示例:

输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

说明:

假设你总是可以到达数组的最后一个位置。

解题思路

这个问题是之前Leetcode 55:跳跃游戏(最详细的解法!!!)的提升。我们先看看这个问题能不能通过动态规划解决,很简单,只是对之前的问题稍加修改,我们这里要考虑的问题是到index的最小步数,也就是之前的[0:index-1]中向前一步能到达index的最小值。

我们在初始化的时候将mem全部初始化为inf,而mem[0]=0即可。

class Solution:
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums_len = len(nums)
        mem = [float('inf')]*nums_len
        mem[0] = 0
        for i in range(1,nums_len):
            for j in range(i):
                if nums[j] + j >= i:
                    mem[i] = min(mem[j]+1, mem[i])
                    break
        
        return mem[-1]

但是这样写法超时了,原因和之前问题一样,一定是有些可以剪枝的思路没有考虑到。我们如果按照之前思路,将这个问题反过来考虑的话,也就是

class Solution:
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums_len = len(nums)
        mem = [float('inf')]*nums_len
        mem[0] = 0
        for i in range(1,nums_len):
            for j in range(i, -1, -1):
                if mem[j] != float('inf') and nums[j] + j >= i:
                    mem[i] = min(mem[j]+1, mem[i])
                    break
        
        return mem[-1]

但是这样思考对吗?对于上面的例子

2   3   1   1   4
0   1

我们考虑1,如果用我们上面写的代码的话,这里我们就需要2步到1,而实际上只要1步,原因在于我们break了,我们没有继续向前查找更小的了。break去了就可以了吗?实际上这又回到了最原始的代码,没有任何剪枝的考量,显然是不合理的。

这个问题通过贪心算法能否解决呢?我们前面步子尽量迈大一点,后面就有更多的空间了啊?显然这种做法是不可行的,因为我们每次求解的是局部最优解,而对于全局来说就不一定是最优解了。那是不是不能用贪心了?我们可以换一个思路,我们先思考跳一步的话最远可以跳多远,接着思考跳两步的话最远可以跳多远,以此类推直到最远的距离大于等于nums.size()-1,那么此时的步数自然就是最少的步数。

所以我们先遍历一遍nums,对于每个index,我们要判断当前steps[step]是不是能大于等于nums_len-1,如果成立,那么我们只要step+1步即可。如果steps[step]<index,也就是说当前step步无法到达index这个位置,我们就要多跳一步step+1。对于我们下一步可以跳多远steps[step+1]这个问题,自然是i in range(index)这个区间内max(nums[i]+i)所决定的,这也是之前问题Leetcode 55:跳跃游戏(最详细的解法!!!)中的思想。

class Solution:
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums_len = len(nums)       
        steps, step = [nums[0]]*nums_len, 0
        for i in range(1, nums_len):
            if steps[step] >= nums_len - 1:
                return step + 1
            if steps[step + 1] < i + nums[i]:
                steps[step + 1] = i + nums[i] 
            if steps[step] <= i:
                step += 1  
                
        return step

非常简洁,非常酷!!!

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/83109778
今日推荐