北川广海の梦

北川广海の梦

动态规划-打家劫舍

7
2025-03-01

先贴一下题目:

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

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

 

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

思路

首先我们需要理一下思路,一个房间能抢到的最大金钱和什么有关系:

  • 当前房间 i 的值

  • 在 i-2 这个房间能抢到的最大值

  • i-1 这个房间我们能抢到的最大值

这是由于规则,我们不能抢劫连续的房间,此时我们用一个 dp 数组,dp[i] 表示第 i 个房间能获得的最大金钱。对于某一个房间 i,我们面临有两种抢劫情况:

  1. 上一个抢的是 i-2 房间,之后我们抢完 i,得到的金钱总数为 dp[i-2]+money[i]

  2. 上一个抢的是 i-1 房间,之后我们跳过 i,此时得到的金钱总数就是 dp[i-1]

此时我们需要比较这两种方案,哪一种的金钱最多,所以我们能获得一个状态转移方程:

dp[i]=max(dp[i-1],dp[i-2]+ money[i])

注意上述条件必须满足 i >=2,也就是从第三座房子开始。

那么对于起始状态,我们很容易能够得到:dp[0] = nums[0],因为第一座房子没有选择的余地。

同理,对于 i=1 时,我们需要对比 money[0] 和 money[1],选择其中最大的入手

综上所述,可以完善状态转移方程:

dp[0]=money[0]
dp[1]=max(money[0],money[1])
dp[i]=max(dp[i-1],dp[i-2]+ money[i]) (i>=2)

题解

func rob(nums []int) int {
    if len(nums) == 1 {
		return nums[0]
	}

	dp := make([]int, len(nums))
	dp[0] = nums[0]
	dp[1] = max(nums[1],nums[0])

	
	for i := 2; i < len(nums); i++ {
		dp[i] = max(dp[i-2]+nums[i], dp[i-1])		
	}

	return dp[len(nums)-1]
}