打劫房屋

来源:互联网 发布:小漠的淘宝店 编辑:程序博客网 时间:2024/04/23 15:34

题目描述:假设你是一个专业的窃贼,准备沿着一条街打劫房屋。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警。给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。

样例:给定 [3, 8, 4], 返回 8.


动态规划问题。因为只是对一排房屋打劫(相当于是对一个序列处理),所以,我们用一个一维表格存储每一步的最优结果。这里,记一维表格为record,record[i] 表示打劫前 i 个房屋能获得的最大收益。那么现在如果已知打劫前 i - 1个房屋的最大收益,那么打劫前 i 个房屋呢。根据题意,不能打劫任意两个相邻的房屋,那么,显然, 打劫前 i 个房屋的收益跟打劫前 i - 1个房屋的策略是有关系的:

1. 如果打劫前 i - 1个房屋时,获得最大收益的策略是要打劫第 i - 1个房屋的,那么,我们就不能打劫第 i 个房屋。打劫前 i 个房屋的最大收益还是打劫前 i - 1个房屋的最大收益

2. 如果打劫前 i - 1个房屋时,获得最大收益的策略是不打劫第 i - 1个房屋的,那么,我们就必须打劫第 i 个房屋(因为要最大收益嘛)。打劫前 i 个房屋的最大收益为:打劫前 i - 2个房屋的最大收益 + 打劫第 i 个房屋的收益


但是,在设计算法的时候,我们并不知道:打劫前 i - 1个房屋时,获得最大收益的策略是要打劫第 i - 1个房屋还是不打劫,所以,对上面的两种情况求取最大值即可。状态转移方程如下:

record[i] = max(record[i - 1], record[i - 2] + A[i])

其中,A为收益列表。

问题初始化的条件是:当列表只有一个值时,最大收益就是这个值,当列表有两个值时,最大收益为他们的最大值。


代码如下:

class Solution:    # @param A: a list of non-negative integers.    # return: an integer    def houseRobber(self, A):        n = len(A)        if n == 0:            return 0        if n == 1:            return A[0]        record = [0, A[0]]        if n >= 2:            for i in range(2, n + 1):                record.append(max(record[i - 1], record[i - 2] + A[i - 1]))        return record[-1]        # write your code here


还可以把一维数组改成一个循环替换的二元组,以节省空间。

class Solution:    # @param A: a list of non-negative integers.    # return: an integer    def houseRobber(self, A):        n = len(A)        if n == 0:            return 0        if n == 1:            return A[0]        record = [0, A[0]]        if n >= 2:            for i in range(2, n + 1):                temp = record[1]                record[1] = max(record[0] + A[i - 1], record[1])                record[0] = temp        return record[1]

这样,时间复杂度O(n),空间复杂度O(1)

0 0
原创粉丝点击