【LeetCode刷题】打家劫舍

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

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

示例 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

解题思路

  1. 状态定义 :用prev_prev记录 "偷到前前间房时的最大金额",prev记录 "偷到前一间房时的最大金额"(替代传统的dp数组,优化空间复杂度至 O (1))。

  2. 状态转移 :对于第i间房,有两种选择:

    • 不偷当前房 :最大金额等于 "偷到前一间房的金额"(即prev);
    • 偷当前房 :最大金额等于 "偷到前前间房的金额 + 当前房的金额"(即prev_prev + nums[i]);取两者的较大值作为当前房的最大金额,并更新前序状态。
  3. 边界处理

    • 空数组直接返回 0;
    • 只有 1 间房时,直接返回该房的金额。

示例验证

  • 示例 1:输入[1,2,3,1]遍历过程:

    • 初始:prev_prev=1prev=2
    • 第 3 间房(值 3):current = max(2, 1+3=4)prev=4
    • 第 4 间房(值 1):current = max(4, 2+1=3) → 最终返回4
  • 示例 2:输入[2,7,9,3,1]遍历过程:

    • 初始:prev_prev=2prev=7
    • 第 3 间房(值 9):current = max(7, 2+9=11)prev=11
    • 第 4 间房(值 3):current = max(11, 7+3=10)prev=11
    • 第 5 间房(值 1):current = max(11, 11+1=12) → 最终返回12

Python代码:

python 复制代码
from typing import List


class Solution:
    def rob(self, nums: List[int]) -> int:
        """
        计算不触动警报时能偷窃的最高金额(空间优化版:O(1)空间复杂度)
        :param nums: 非负整数数组,每个元素代表对应房屋的现金金额
        :return: 能偷窃的最高金额
        """
        # 边界条件1:空数组(题目提示长度≥1,此判断为鲁棒性补充)
        if not nums:
            return 0
        # 边界条件2:只有1间房,直接偷这间
        if len(nums) == 1:
            return nums[0]

        # 状态初始化:
        # prev_prev: 偷到「前前间房」时的最大金额(对应dp[i-2])
        # prev: 偷到「前一间房」时的最大金额(对应dp[i-1])
        prev_prev = nums[0]
        prev = max(nums[0], nums[1])  # 前两间房选金额大的偷

        # 从第3间房开始遍历(索引2),逐间推导最大金额
        for i in range(2, len(nums)):
            # 状态转移核心:
            # 偷当前房:不能偷前一间,金额=prev_prev + 当前房金额
            # 不偷当前房:金额=prev(前一间的最大金额)
            current = max(prev, prev_prev + nums[i])

            # 更新前序状态:为下一间房的计算做准备
            prev_prev, prev = prev, current

        # 最终prev存储的是偷到最后一间房时的最大金额
        return prev

    def rob_dp_array(self, nums: List[int]) -> int:
        """
        传统DP数组版(O(n)空间复杂度,更易理解)
        :param nums: 房屋金额数组
        :return: 最高偷窃金额
        """
        if not nums:
            return 0
        n = len(nums)
        if n == 1:
            return nums[0]

        # dp[i]:偷到第i间房(索引i)时的最大金额
        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 - 1], dp[i - 2] + nums[i])

        return dp[-1]


# ---------------------- 测试用例 ----------------------
if __name__ == "__main__":
    solution = Solution()

    # 测试示例1
    nums1 = [1, 2, 3, 1]
    res1 = solution.rob(nums1)
    print(f"示例1输入:{nums1}")
    print(f"示例1输出(空间优化版):{res1}(预期:4)")
    print(f"示例1输出(DP数组版):{solution.rob_dp_array(nums1)}(预期:4)")
    print("-" * 30)

    # 测试示例2
    nums2 = [2, 7, 9, 3, 1]
    res2 = solution.rob(nums2)
    print(f"示例2输入:{nums2}")
    print(f"示例2输出(空间优化版):{res2}(预期:12)")
    print(f"示例2输出(DP数组版):{solution.rob_dp_array(nums2)}(预期:12)")
    print("-" * 30)

    # 额外测试:单元素数组
    nums3 = [5]
    res3 = solution.rob(nums3)
    print(f"额外测试(单元素):{nums3} → {res3}(预期:5)")

    # 额外测试:两元素数组
    nums4 = [3, 7]
    res4 = solution.rob(nums4)
    print(f"额外测试(两元素):{nums4} → {res4}(预期:7)")

LeetCode提交代码:

python 复制代码
from typing import List

class Solution:
    def rob(self, nums: List[int]) -> int:
        # 处理空数组或单元素数组的特殊情况
        if not nums:
            return 0
        if len(nums) == 1:
            return nums[0]
        
        # 初始化前两个状态:prev_prev对应"前前间房的最大金额",prev对应"前一间房的最大金额"
        prev_prev = nums[0]
        prev = max(nums[0], nums[1])
        
        # 从第3间房开始遍历(索引为2)
        for i in range(2, len(nums)):
            # 当前房的最大金额 = max(不偷当前房(取前一间的金额), 偷当前房(取前前间+当前房的金额))
            current = max(prev, prev_prev + nums[i])
            # 更新前序状态
            prev_prev, prev = prev, current
        
        return prev

程序运行结果展示:

bash 复制代码
示例1输入:[1, 2, 3, 1]
示例1输出(空间优化版):4(预期:4)
示例1输出(DP数组版):4(预期:4)
------------------------------
示例2输入:[2, 7, 9, 3, 1]
示例2输出(空间优化版):12(预期:12)
示例2输出(DP数组版):12(预期:12)
------------------------------
额外测试(单元素):[5] → 5(预期:5)
额外测试(两元素):[3, 7] → 7(预期:7)

总结

本文解决房屋盗窃问题,要求在不相邻房屋中获取最高金额。采用动态规划方法,定义状态prev_prevprev分别表示前前间和前一间的最大金额。状态转移方程为current = max(prev, prev_prev + nums[i]),优化空间复杂度至O(1)。示例验证显示算法正确性,如输入[1,2,3,1]输出4,输入[2,7,9,3,1]输出12。Python代码实现包含空间优化版和传统DP数组版,边界处理覆盖空数组和单元素情况。运行结果与预期一致,证明算法有效性。

相关推荐
uesowys7 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
ValhallaCoder7 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
董董灿是个攻城狮7 小时前
AI 视觉连载1:像素
算法
智驱力人工智能7 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
猫头虎8 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
孞㐑¥8 小时前
算法——BFS
开发语言·c++·经验分享·笔记·算法
八零后琐话8 小时前
干货:程序员必备性能分析工具——Arthas火焰图
开发语言·python
月挽清风8 小时前
代码随想录第十五天
数据结构·算法·leetcode
XX風8 小时前
8.1 PFH&&FPFH
图像处理·算法