【附源码】Python :打家劫舍

系列文章目录

Python 算法学习:打家劫舍问题


文章目录


一、算法需求

"打家劫舍"问题是一个经典的动态规划问题,通常用来描述一个小偷在一条街上偷窃房屋的场景。每间房屋都有一定数量的现金,小偷需要决定偷哪些房屋以最大化他的收益。但是,小偷面临一个限制:如果两间相邻的房屋在同一晚上被偷,那么防盗系统会触发报警。因此,小偷不能偷窃相邻的房屋。


二、解题思路

动态规划: 定义一个数组 dp,其中 dp[i] 表示到第 i 间房屋为止能偷到的最大金额。状态转移方程是 dp[i] = max(dp[i-1], dp[i-2] + nums[i]),表示可以选择偷当前房子(前提是不偷前一个房子)或者不偷当前房子(延续前一个房子的决策)。

贪心算法: 虽然不总是最优,但可以作为一种尝试。在每一步选择当前能获得的最大金额,而不考虑未来的房子。

递归: 通过递归函数模拟决策过程,考虑偷或不偷当前房子,并取两种选择中的最大值。

优化空间: 使用两个变量代替数组,减少空间复杂度。


三、具体方法+源码

方法1:动态规划(自底向上)

状态定义:dp[i] 表示到第 i 个房子为止能偷到的最大金额。

计算过程:

dp[0] = 2(只考虑第一个房子)

dp[1] = max(2, 7) = 7(考虑第一个和第二个房子)

dp[2] = max(7, 2+9) = 9(考虑第二个和第三个房子)

dp[3] = max(9, 7+3) = 10(考虑第三个和第四个房子)

dp[4] = max(10, 9+1) = 12(考虑第四个和第五个房子)

结果:12

代码如下:

python 复制代码
def rob1(nums):
    if not nums:
        return 0
    if len(nums) == 1:
        return nums[0]
    dp = [0] * len(nums)
    dp[0] = nums[0]
    dp[1] = max(nums[0], nums[1])
    for i in range(2, len(nums)):
        dp[i] = max(dp[i-1], dp[i-2] + nums[i])
    return dp[-1]

# 测试
nums = [2, 7, 9, 3, 1]
print("最高金额:", rob1(nums))

方法2:动态规划(自顶向下)

计算过程:

从 rob(0) 开始

rob(1) = max(rob(2), rob(3)) = max(7, 9) = 9

rob(2) = max(rob(3), rob(4) + 2) = max(9, 10) = 10

rob(3) = max(rob(4), rob(5) + 3) = max(9, 12) = 12

rob(4) = max(rob(5), rob(6) + 1) = max(7, 12) = 12

结果:12

代码如下:

python 复制代码
def rob2(nums):
    memo = {}
    def rob(i):
        if i >= len(nums):
            return 0
        if i in memo:
            return memo[i]
        memo[i] = max(rob(i+1), nums[i] + rob(i+2))
        return memo[i]
    return rob(0)

# 测试
nums = [2, 7, 9, 3, 1]
print("最高金额:", rob2(nums))

方法3:优化的动态规划

计算过程:

prev = 2, curr = 7

prev = 7, curr = 9

prev = 9, curr = 10

prev = 10, curr = 12

结果:12

代码如下:

python 复制代码
def rob3(nums):
    if not nums:
        return 0
    if len(nums) == 1:
        return nums[0]
    prev, curr = 0, 0
    for num in nums:
        prev, curr = curr, max(prev + num, curr)
    return curr

# 测试
nums = [2, 7, 9, 3, 1]
print("最高金额:", rob3(nums))

方法4:递归

计算过程:

helper(0) = max(helper(1), helper(2) + 2) = max(7, 9) = 9

helper(1) = max(helper(2), helper(3) + 7) = max(9, 10) = 10

helper(2) = max(helper(3), helper(4) + 9) = max(10, 12) = 12

helper(3) = max(helper(4), helper(5) + 3) = max(9, 12) = 12

helper(4) = max(helper(5), 1) = 12

结果:12

代码如下:

python 复制代码
def rob4(nums):
    def helper(i):
        if i == len(nums):
            return 0
        if i == len(nums) - 1:
            return nums[i]
        return max(helper(i+1), nums[i] + helper(i+2))
    return helper(0)

# 测试
nums = [2, 7, 9, 3, 1]
print("最高金额:", rob4(nums))

总结

这个问题在算法学习中非常重要,因为它展示了如何使用动态规划解决具有重叠子问题和最优子结构特性的问题。它也常用于面试中,考察候选人对动态规划的理解和应用能力。

这个问题的变种也很多,比如考虑环形街道的情况,或者房屋之间的防盗系统有不同的触发条件等。

相关推荐
databook3 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar4 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780515 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_5 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机11 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机12 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机12 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机12 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i12 小时前
drf初步梳理
python·django
每日AI新事件12 小时前
python的异步函数
python