213.打家劫舍II

class Solution:
    def rob0(self, nums: List[int]) -> int:
        dp =[0]*(len(nums)+1)
        dp[0]=0
        dp[1]=nums[0]
        for i in range(2,len(nums)+1):
            dp[i]=max(dp[i-1],dp[i-2]+nums[i-1])
        return dp[-1]
    def rob(self, nums: List[int]) -> int:
        if len(nums)<=1:
            return nums[0]
        nums_with_first =nums[0:len(nums)-1]
        nums_without_first =nums[1:len(nums)]
        result= max(self.rob0(nums_with_first),self.rob0(nums_without_first))
        return result
from typing import List # 确保导入 List 类型

class Solution:
    # 辅助函数:解决线性排列的“打家劫舍 I”问题
    def rob0(self, nums: List[int]) -> int:
        """
        计算线性排列的房屋 nums 中能偷窃到的最高金额。
        假设调用此函数时,nums 列表长度至少为 1 (由主函数 rob 保证)。
        """
        n = len(nums)

        # 因为主函数 rob 保证了调用此函数时 n >= 1,
        # 我们可以简化这里的边界处理。
        # 如果 n == 0: return 0  (理论上不会发生)
        if n == 1:
            return nums[0] # 如果只有一个房子,直接返回其金额

        # 创建 DP 数组,大小为 n+1
        # dp[i] 表示考虑前 i 个房子 (索引 0 到 i-1) 能偷到的最大金额
        dp = [0]*(n + 1)
        # dp[0] = 0: 不偷任何房子,金额为 0
        dp[0] = 0
        # dp[1]: 只考虑第一个房子 (nums[0]),最大金额就是 nums[0]
        dp[1] = nums[0]

        # 从第 2 个房子开始计算 (对应 nums 索引为 1,dp 索引为 2)
        for i in range(2, n + 1):
            # 递推关系:
            # 偷第 i 个房子 (nums[i-1]) 的最大金额 = dp[i-2] + nums[i-1]
            # 不偷第 i 个房子 (nums[i-1]) 的最大金额 = dp[i-1]
            # 取两者中的较大值
            dp[i] = max(dp[i-1], dp[i-2] + nums[i-1])

        # 返回考虑所有 n 个房子的最大金额,即 dp[n]
        # dp[-1] 是 Python 访问列表最后一个元素的便捷方式,即 dp[n]
        return dp[-1]

    # 主函数:解决环形排列的“打家劫舍 II”问题
    def rob(self, nums: List[int]) -> int:
        """
        计算环形排列的房屋 nums 中能偷窃到的最高金额。
        第一个房子和最后一个房子不能同时偷。
        """
        n = len(nums)

        # --- 边界情况处理 ---
        # 如果没有房子
        if n == 0:
            return 0
        # 如果只有一个房子
        if n == 1:
            return nums[0]
        # 如果只有两个房子 (n=2), 因为不能同时偷,所以只能偷金额较大的那一个
        # 这个情况其实会被下面的主要逻辑覆盖,但也可以单独处理
        # if n == 2:
        #     return max(nums[0], nums[1])
        # --------------------

        # --- 主要逻辑:分解为两个线性问题 ---
        # 因为第一个和最后一个房子不能同时偷,问题分解为:
        # 1. 偷窃范围是 [0, n-2] (不偷最后一个房子)
        # 2. 偷窃范围是 [1, n-1] (不偷第一个房子)
        # 取这两种情况的最大值即可。

        # 情况 1: 考虑房子 0 到 n-2 (不包括最后一个房子 nums[n-1])
        # 创建切片 nums[0:n-1] (注意:切片不包括索引 n-1 的元素)
        nums_with_first = nums[0 : n-1]

        # 情况 2: 考虑房子 1 到 n-1 (不包括第一个房子 nums[0])
        # 创建切片 nums[1:n] (注意:切片从索引 1 开始)
        nums_without_first = nums[1 : n]

        # 分别调用辅助函数 rob0 计算两种情况下的最大金额
        # self.rob0(nums_with_first) 计算情况 1 的最大值
        # self.rob0(nums_without_first) 计算情况 2 的最大值
        result = max(self.rob0(nums_with_first), self.rob0(nums_without_first))

        # 返回两种情况中的最大值作为最终结果
        return result
       
        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值