使用(0, i]这种定义的时间复杂度为何会是O(n)级别的复杂度而不是(i, n-1]的O(n^2)

来源:9-4 状态的定义和状态转移 House Robber

Flight0

2017-06-14

class Solution(object):
    def rob(self, nums):
        length = len(nums)
        memo = [0 for index in range(length)]
        if length == 0:
            return 0
        elif length == 1:
            return nums[0]
        elif length == 2:
            return max(nums[0], nums[1])
        memo[0] = nums[0]
        memo[1] = nums[1]
        memo[2] = memo[0] + nums[2]
        for x in range(3, length):
            memo[x] = max(memo[x - 2], memo[x - 3]) + nums[x]
        return max(memo[length - 1], memo[length - 2])

代码是这样的,同样是动态规划,状态的定义不同为何会影响算法的时间复杂度,还是说定义为(i, n-1]的状态还有更好的写法。谢谢老师

写回答

1回答

liuyubobobo

2017-06-15

非常非常赞!


事实上,使用你的思路,很容易写出使用[i,n)的定义,且复杂度为O(n)级别的代码。我直接修改你的python代码,具体如下:

class Solution(object):
    def rob(self, nums):
        length = len(nums)
        memo = [0 for index in range(length)]
        if length == 0:
            return 0
        elif length == 1:
            return nums[length-1]
        elif length == 2:
            return max(nums[length-1], nums[length-2])
        memo[length-1] = nums[length-1]
        memo[length-2] = nums[length-2]
        memo[length-3] = memo[length-1] + nums[length-3]
        for x in reversed(range(0,length-3)):
            memo[x] = max(memo[x + 2], memo[x + 3]) + nums[x]
        return max(memo[0], memo[1])


仔细思考,实际上,是这个思路的状态转移过程和课程中讲的略有不同。以你的[0,i]定义为例。课程中的思路是,如果选取第i个元素,就要检查这第i个元素和之前的那种盗取策略匹配,而这个检查检查了从memo[0]到memo[i-2]的所有可能。但是,根据我们的状态定义,memo[x]中存储的并不是“一定”要偷取第x个房子,而是考虑[0...x]中所有房子的结果。所以其实我们没必要搜索从memo[0]到memo[i-2]的所有可能,memo[i-2]中就蕴含了这个最大值。


备课的时候太沉浸在将组合问题的动态规划结构,忽略了这个最优子性质。非常抱歉。感谢你的好问题。有时间可以加我的微信:liuyubobobo。我会发给你一个小红包:)

13
1
Flight0
谢谢老师,我懂了
2017-06-16
共1条回复

玩转算法面试-- Leetcode真题分门别类讲解

课程配套大量BAT面试真题,高频算法题解析,强化训练

7410 学习 · 1150 问题

查看课程