Python每日一练(20230516) 打家劫舍 I\II\III\IV HouseRobber

简介: Python每日一练(20230516) 打家劫舍 I\II\III\IV HouseRobber

leetcode 对应题号: 198、213、337、2560


1. 打家劫舍 I House Robber i


你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。


给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。


示例 1:

输入:[1,2,3,1]

输出:4

解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。

    偷窃到的最高金额 = 1 + 3 = 4 。


示例 2:

输入:[2,7,9,3,1]

输出:12

解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。

    偷窃到的最高金额 = 2 + 9 + 1 = 12 。


提示:

   1 <= nums.length <= 100

   0 <= nums[i] <= 400


代码:

class Solution:
    def rob1(self, nums):
        if not nums:
            return 0
        n = len(nums)
        if n == 1:
            return nums[0]
        dp = [0] * n
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        for i in range(2, n):
            dp[i] = max(dp[i-2]+nums[i], dp[i-1])
        return dp[n-1]
    def rob2(self, nums):
        if not nums:
            return 0
        n = len(nums)
        if n == 1:
            return nums[0]
        prepre, pre = nums[0], max(nums[0], nums[1])
        for i in range(2, n):
            cur = max(prepre+nums[i], pre)
            prepre, pre = pre, cur
        return pre
    def rob3(self, nums):
        mem = [-1] * len(nums)
        return helper(nums, mem, len(nums)-1)
def helper(nums, mem, i):
    if i < 0:
        return 0
    if mem[i] >= 0:
            return mem[i]
    res = max(helper(nums, mem, i-2)+nums[i], helper(nums, mem, i-1))
    mem[i] = res
    return res
if __name__ == '__main__':
    solution = Solution()
    nums = [1, 2, 3, 1]
    print(solution.rob1(nums))
    print(solution.rob2(nums))
    print(solution.rob3(nums))
    nums = [2, 7, 9, 3, 1]
    print(solution.rob1(nums))
    print(solution.rob2(nums))
    print(solution.rob3(nums))


输出:

4

4

4

12

12

12


2. 打家劫舍 II House Robber ii


你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。


给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。


示例 1:

输入:nums = [2,3,2]

输出:3

解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。


示例 2:

输入:nums = [1,2,3,1]

输出:4

解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。


    偷窃到的最高金额 = 1 + 3 = 4 。


示例 3:

输入:nums = [1,2,3]

输出:3


提示:

   1 <= nums.length <= 100

   0 <= nums[i] <= 1000


代码:

def robII(nums):
    if not nums:
        return 0
    n = len(nums)
    if n == 1:
        return nums[0]
    return max(rob_range(nums, 0, n-2), rob_range(nums, 1, n-1))
def rob_range(nums, start, end):
    dp = [0] * (end-start+1)
    dp[0] = nums[start]
    dp[1] = max(nums[start], nums[start+1])
    for i in range(2, end-start+1):
        dp[i] = max(dp[i-2]+nums[start+i], dp[i-1])
    return dp[-1]
if __name__ == '__main__':
    nums = [2,3,2]
    print(robII(nums))
    nums = [1,2,3,1]
    print(robII(nums))
    nums = [1,2,3]
    print(robII(nums))

3

4

3


3. 打家劫舍 III House Robber iii


小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。


除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。


给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。


示例 1:

cc81a58f0396ec9853c8e84535267d59.jpeg


输入: root = [3,2,3,null,3,null,1]

输出: 7

解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7

示例 2:

73795a34654b50ab1a1b033d49616826.jpeg

输入: root = [3,4,5,1,3,null,1]

输出: 9

解释: 小偷一晚能够盗取的最高金额 4 + 5 = 9


提示:

  • 树的节点数在 [1, 10^4] 范围内
  • 0 <= Node.val <= 10^4

代码:

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def rob(self, root: TreeNode) -> int:
        def _rob(node):
            if not node:
                return (0, 0)
            left = _rob(node.left)
            right = _rob(node.right)
            rob = node.val + left[1] + right[1]
            not_rob = max(left) + max(right)
            return (rob, not_rob)
        return max(_rob(root))
def listToTree(lst: list) -> TreeNode:
    if not lst:
        return None
    root = TreeNode(lst[0])
    queue = [root]
    i = 1
    while i < len(lst):
        node = queue.pop(0)
        if lst[i] is not None:
            node.left = TreeNode(lst[i])
            queue.append(node.left)
        i += 1
        if i < len(lst) and lst[i] is not None:
            node.right = TreeNode(lst[i])
            queue.append(node.right)
        i += 1
    return root
if __name__ == '__main__':
    solution = Solution()
    null = None
    root = listToTree([3,2,3,null,3,null,1])
    print(solution.rob(root))
    root = listToTree([3,4,5,1,3,null,1])
    print(solution.rob(root))

输出:

7

9


4. 打家劫舍 IV House Robber iv


沿街有一排连续的房屋。每间房屋内都藏有一定的现金。现在有一位小偷计划从这些房屋中窃取现金。

由于相邻的房屋装有相互连通的防盗系统,所以小偷 不会窃取相邻的房屋 。


小偷的 窃取能力 定义为他在窃取过程中能从单间房屋中窃取的 最大金额 。


给你一个整数数组 nums 表示每间房屋存放的现金金额。形式上,从左起第 i 间房屋中放有 nums[i] 美元。


另给你一个整数 k ,表示窃贼将会窃取的 最少 房屋数。小偷总能窃取至少 k 间房屋。


返回小偷的 最小 窃取能力。


示例 1:

输入:nums = [2,3,5,9], k = 2

输出:5


解释:

小偷窃取至少 2 间房屋,共有 3 种方式:

- 窃取下标 0 和 2 处的房屋,窃取能力为 max(nums[0], nums[2]) = 5 。

- 窃取下标 0 和 3 处的房屋,窃取能力为 max(nums[0], nums[3]) = 9 。

- 窃取下标 1 和 3 处的房屋,窃取能力为 max(nums[1], nums[3]) = 9 。

因此,返回 min(5, 9, 9) = 5 。


示例 2:

输入:nums = [2,7,9,3,1], k = 2

输出:2

解释:共有 7 种窃取方式。窃取能力最小的情况所对应的方式是窃取下标 0 和 4 处的房屋。返回 max(nums[0], nums[4]) = 2 。


提示:

   1 <= nums.length <= 10^5

   1 <= nums[i] <= 10^9

   1 <= k <= (nums.length + 1)/2


代码:

from typing import List
class Solution:
    def minCapability(self, nums: List[int], k: int) -> int:
        left = min(nums)
        right = max(nums)
        dp = [0] * (len(nums) + 2)
        while left <= right:
            mid = left + (right - left) // 2
            for i in range(len(nums)):
                dp[i + 2] = dp[i + 1]
                if nums[i] <= mid:
                    dp[i + 2] = max(dp[i + 2], dp[i] + 1)
            if dp[len(nums) + 1] >= k:
                right = mid - 1
            else:
                left = mid + 1
        return left
if __name__ == '__main__':
    s = Solution()
    nums = [2, 3, 5, 9]
    print(s.minCapability(nums, 2))
    nums = [2, 7, 9, 3, 1]
    print(s.minCapability(nums, 2))


输出:

5

2



目录
相关文章
|
2月前
|
移动开发 Python
【Leetcode刷题Python】337. 打家劫舍 III
LeetCode 337题 "打家劫舍 III" 的Python解决方案,使用递归和动态规划计算小偷在二叉树结构的房屋中不触发警报的情况下能够盗取的最高金额。
34 1
【Leetcode刷题Python】337. 打家劫舍 III
|
2月前
|
Python
【Leetcode刷题Python】213. 打家劫舍 II
LeetCode 213题 "打家劫舍 II" 的Python解决方案,通过动态规划处理环形房屋的偷窃问题,计算在不触发警报的情况下能够偷窃到的最高金额。
16 1
|
2月前
|
Python
【Leetcode刷题Python】198. 打家劫舍
LeetCode 198题 "打家劫舍" 的Python解决方案,使用动态规划计算小偷在不触发警报的情况下一夜之内能够偷窃到的最高金额。
34 1
|
5月前
|
Python 人工智能
讯飞星火、文心一言和通义千问同时编“贪吃蛇”游戏,谁会胜出?
讯飞星火、文心一言和通义千问同时编“贪吃蛇”游戏,谁会胜出?
88 1
讯飞星火、文心一言和通义千问同时编“贪吃蛇”游戏,谁会胜出?
|
5月前
|
Shell Unix Linux
Linux 终端命令之文件浏览(3) less
Linux 终端命令之文件浏览(3) less
60 0
Linux 终端命令之文件浏览(3) less
|
5月前
|
Rust
Rust 编程小技巧摘选(8)
Rust 编程小技巧摘选(8)
187 0
Rust 编程小技巧摘选(8)
|
5月前
|
算法 C++ 机器人
力扣 C++|一题多解之动态规划专题(1)
力扣 C++|一题多解之动态规划专题(1)
59 0
力扣 C++|一题多解之动态规划专题(1)
|
5月前
|
C++ Python 索引
Python Numpy入门基础(二)数组操作
Python Numpy入门基础(二)数组操作
51 0
Python Numpy入门基础(二)数组操作
|
5月前
|
C++ 存储
力扣C++|一题多解之数学题专场(1)
力扣C++|一题多解之数学题专场(1)
45 0
力扣C++|一题多解之数学题专场(1)
|
1天前
|
机器学习/深度学习 人工智能 数据可视化
Python比较适合哪些场景的编程?
Python比较适合哪些场景的编程?
14 7
下一篇
无影云桌面