Jump Game II

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position. 

Your goal is to reach the last index in the minimum number of jumps.

For example:
Given array A = [2,3,1,1,4]

The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)

 这一题是Jump Game的follow up。既然有判断能不能,就会有最少多少步可以达到的问法。延续之前的DP和Greedy,这题同样有两种解法。

首先DP,DP的转移方程是f(i)=Min(f(j)+1)(j<i && nums[j]+j >= i)。和之前的OR一样,min的存在使DP是二维的,代码如下:

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        res = [sys.maxint]*len(nums)
        res[0] = 0
        for i in xrange(1,len(nums)):
            for j in xrange(i):
                if nums[j] != sys.maxint and nums[j] + j >= i:
                   res[i] = min(res[i],res[j]+1)
        return res[-1]

上述代码可以优化,首先可以证明一点,f(j)<=f(i)(j<i)。即到达数组之前点的步数不多于到达后面的步数。一个是如果j在f(i)最后一步的范围里,则减小步伐就可以到达,f(i)=f(j)。如果不在这个范畴,说明用更小的步数就可以到达。所以上述代码可以剪枝,最里层循环,从小到大,一旦可以找到到达i的j,就可以break,因为后面的小于i的j的步数不会更优。优化代码如下:

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        res = [sys.maxint]*len(nums)
        res[0] = 0   #bound situation that can't be handled by the normal formulation.
        for i in xrange(1,len(nums)):
            for j in xrange(i):
                if res[j] != sys.maxint and nums[j]+j >= i:
                    res[i] = res[j]+1
                    break    #剪枝,break

return res[-1]

上述优化过的DP解法依然在Leetcode里超时,所以不得不使用贪心算法。

和之前在Jump Game里面的思路很像,我们维护一个当前可以到达的最远距离curMax,但是这一题需要计算步数,所以一个办法是维护一个之前步可以到达的最远距离lastMax,然后在之前步所走的范围里寻找当前步可以到达的最远距离,是BFS的思想。在更新步数时,需要更新lastMax,代码如下:

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        step, lastMax, curMax, i = 0, 0, 0, 0
        while curMax < len(nums)-1:
            step += 1
            lastMax = curMax
            while i <= lastMax:
                curMax = max(curMax,nums[i]+i)
                i += 1 
            if lastMax == curMax: #防止连续为0,无解的情况
                return -1
        return step

可以看到step为1时,lastMax为0,此时curMax为第一步可以到达的最远距离。所以一旦curMax>=len(nums)-1,就说明已经可以到达终点了。

这题可以有相当多的follow up,比如求最短路径的具体跳转地点,思路是维护一个动态可增的数组,比如list或者vector,max(curMax,nums[i]+i)换成时机的比较,如果有比较则更新值。每一步的跳转的地方都是上一步可以到达的最远的点。

注意数组中有0,比如[2,3,0,0,1],用上述的贪心是也是解的。

posted on 2016-05-23 21:03  Sheryl Wang  阅读(143)  评论(0编辑  收藏  举报

导航