美文网首页
LintCode-打劫房屋I、 II(环状数据的处理)、III

LintCode-打劫房屋I、 II(环状数据的处理)、III

作者: 想当厨子的程序员 | 来源:发表于2018-09-24 10:21 被阅读0次

    I

    描述

    假设你是一个专业的窃贼,准备沿着一条街打劫房屋。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警。

    给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。

    样例

    给定 [3, 8, 4], 返回 8.

    挑战

    O(n) 时间复杂度 且 O(1) 存储。

    代码

    class Solution:
        """
        @param A: An array of non-negative integers
        @return: The maximum amount of money you can rob tonight
        """
        def houseRobber(self, A):
            # write your code here
            dp = [0 for i in range(len(A))]
            if len(A) == 0:
                return 0
            dp[0] = A[0]
            if len(A) == 1:
                return dp[0]
            dp[1] = A[1]   
            if len(A) == 2:
                return max(dp[0], dp[1])
            for i in range(2, len(A)):
                dp[i] = max(dp[i-2]+A[i], dp[i-1])
            return dp[-1]
    

    常规的求最大小动态规划。

    题目来源

    https://www.lintcode.com/problem/house-robber/description

    II

    描述

    在上次打劫完一条街道之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子围成了一个圈,这就意味着第一间房子和最后一间房子是挨着的。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警

    给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。

    这题是House Robber的扩展,只不过是由直线变成了圈

    样例

    给出nums = [3,6,4], 返回 6, 你不能打劫34所在的房间,因为它们围成一个圈,是相邻的.

    代码

    class Solution:
        """
        @param nums: An array of non-negative integers.
        @return: The maximum amount of money you can rob tonight
        """
        def houseRobber2(self, nums):
            # write your code here
            n = len(nums)
            if n <= 0:
                return 0
            elif n <= 3:
                return max(nums)
            new_nums = nums[:n-1]     
            result = self.houseRobber(new_nums)
            new_nums = nums[1:] 
            result = max(result, self.houseRobber(new_nums))
            return result
            
        def houseRobber(self, A):
            # write your code here
            dp = [0 for i in range(len(A))]
            dp[0] = A[0]
            dp[1] = max(A[0], A[1])   
            for i in range(2, len(A)):
                dp[i] = max(dp[i-2]+A[i], dp[i-1])
            return dp[-1]
    

    解决环状结构数据其实也很容易,只需要“掐头”、“去尾”分成两个数据集合分别按照直线的方法处理即可,因为这样的情况下头和尾是不能相遇的,所以,就模拟了头尾相连不可以同时选的情况。

    题目来源

    https://www.lintcode.com/problem/house-robber-ii/description

    III

    描述

    在上次打劫完一条街道之后和一圈房屋之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子组成的区域比较奇怪,聪明的窃贼考察地形之后,发现这次的地形是一颗二叉树。与前两次偷窃相似的是每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且当相邻的两个房子同一天被打劫时,该系统会自动报警。

    算一算,如果今晚去打劫,你最多可以得到多少钱,当然在不触动报警装置的情况下。

    这题是House RobberHouse Robber II的扩展,只不过这次地形由直线和圈变成了二叉树

    样例

      3
     / \
    2   3
     \   \ 
      3   1
    
    

    窃贼最多能偷窃的金钱数是 3 + 3 + 1 = 7.

        3
       / \
      4   5
     / \   \ 
    1   3   1
    
    

    窃贼最多能偷窃的金钱数是 4 + 5 = 9.

    代码

    """
    Definition of TreeNode:
    class TreeNode:
        def __init__(self, val):
            self.val = val
            self.left, self.right = None, None
    """
    
    class Solution:
        """
        @param root: The root of binary tree.
        @return: The maximum amount of money you can rob tonight
        """
        def houseRobber3(self, root):
            # write your code here
            self.Globals = dict([])
            return self.Dfs(root)
            
        def Dfs(self, root):
            if root == None:
                return 0
            if self.Globals. __contains__(root):
                return self.Globals[root]
            val = 0
            if root.left != None:
                val += self.Dfs(root.left.left) + self.Dfs(root.left.right)
            if root.right != None:
                val += self.Dfs(root.right.left) + self.Dfs(root.right.right)
            value = max(root.val+val, self.Dfs(root.left)+self.Dfs(root.right))
            self.Globals[root] = value 
            return value
    

    遍历数据的方式还是DFS,值得注意的是, 父节点取了,就只能取子节点的子节点,然后用他们的和,与子节点对比记录最大值,为何用到DP,是为了防止搜索重复的节点,因为很显然

    val += self.Dfs(root.left.left) + self.Dfs(root.left.right)
    value = max(root.val+val, self.Dfs(root.left)+self.Dfs(root.right))
    

    肯定会有节点重复。
    另外值得一提的是,dict的keys、vals都可以是值、字符串、对象。这个在以前写的OBJ轮子里,是用过的。
    另外python2中的dict.has_key(key)方法在python3中更新为了dict.contains(key)方法。

    #Python 3.X 里不包含 has_key() 函数,被 __contains__(key) 替代:
    dict3 = {'name':'z','Age':7,'class':'First'};
    print("Value : ",dict3.__contains__('name'))
    print("Value : ",dict3.__contains__('sex'))
    

    执行结果:

    Value :  True
    Value :  False
    

    题目来源

    https://www.lintcode.com/problem/house-robber-iii/description

    相关文章

      网友评论

          本文标题:LintCode-打劫房屋I、 II(环状数据的处理)、III

          本文链接:https://www.haomeiwen.com/subject/ggucoftx.html