Jump Game

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. 

Determine if you are able to reach the last index.

For example:
A = [2,3,1,1,4], return true.

A = [3,2,1,0,4], return false.

这是Jump Game系列的第一题,判断根据给出的数组能不能到达最后一个index。如果可以的话,则返回True。

使用DP的话,设f(i)表示为能否到达index为i的位置。分解子问题则 f(i) = OR(f(j) and j + A[j] > i)即如果小于i的index j上如果跳一步可以到达i, 则i可以到达。根据这个给出DP的代码如下:

class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        if not nums:
            return true
        n = len(nums)
        res = [False]*n
        res[0] = True
        for i in xrange(1,n):
            for j in xrange(i,-1,-1):     #倒序,可以减少遍历的次数
                if res[j] == True and nums[j]+j>=i:  #剪枝,防止超时。
                    res[i] = True
                    break
        return res[-1]

注意因为有多种可能的路径,所以一旦找到使OR为真的j,就需要进行剪枝。否则DP的复杂度就是O(n^2),在Leetcode上会超时。

这一题最优的解法为贪心,O(n)。做法是维护一个在index i时可到达的最远距离reach,这个reach不一定是在index i处跳nums[i]到达的,可以是在i之前的index上到达的,是一个历史最优。

1.能继续循环,处理到i的条件为i<=reach。即i处在历史可到达的最远距离范围中。

2.reach的更新是 reach = max(reach,i+nums[i]).

3.判断可以达到终点的条件是reach>= len(nums)-1.

因为每一步维护的是一个局部最优解,所以是贪心的解法,代码如下:

class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        if not nums:
            return True
        reach, i = 0, 0 
        while i <= reach and reach < len(nums):
            reach = max(reach,nums[i]+i)
            i = i+1
        return reach >= len(nums)-1

空间复杂度也为O(n)。

上述这种解法也可以认为是DP,和Maximum Subarray非常类似,可以认为我们维护了一个local最优,即当前位置可以跳到的最远距离:nums[i]+i,全局最优:历史位置上可以到达的最远距离:即reach.每次更新局部最优时,同步更新全局最优。

 

posted on 2016-05-23 19:48  Sheryl Wang  阅读(177)  评论(0编辑  收藏  举报

导航