一、198. 打家劫舍
题目链接:198. 打家劫舍 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——198. 打家劫舍
视频讲解:动态规划,偷不偷这个房间呢?| LeetCode:198.打家劫舍_哔哩哔哩_bilibili
动态规划五部曲:
1. 确定 dp 数组及下标含义:考虑下标 i (包含)所能偷的最大钱币数为 dp[ i ]
2. 确定递推公式:
偷 i:dp[ i - 2 ] + nums[ i ],因为dp[i - 1] 一定不能被偷,所以找 dp[ i -2 ]
不偷i:dp[ i - 1],表示 i - 1之前所偷最大钱币数,不一定偷 i - 1,i - 1 仅仅是一个考虑范围
递推公式:dp[ i ] = max(dp[ i - 2 ] + nums[ i ], dp[ i - 1])
3. 确定dp数组如何初始化:dp[ 0 ] = nums[ 0 ], dp[ 1 ] = max(nums[ 0 ], nums[ 1 ])
4. 确定遍历顺序:从小到大遍历,且从2开始
for i in range(2, len(nums) + 1):
5. 举例推导dp数组。
class Solution:
def rob(self, nums: List[int]) -> int:
# 如果没有房屋,返回0
if len(nums) == 0:
return 0
# 如果有一间房屋,返回唯一金额
if len(nums) == 1:
return nums[0]
# 创建dp数组
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 - 2] + nums[i], dp[i - 1])
return dp[-1]
二、213. 打家劫舍II
题目链接:213. 打家劫舍 II - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——213. 打家劫舍II
视频讲解:动态规划,房间连成环了那还偷不偷呢?| LeetCode:213.打家劫舍II_哔哩哔哩_bilibili
思路:
case 1. 即不考虑头元素,也不考虑尾元素
case 2. 考虑头元素,构成一个线性数组
case 3. 考虑尾元素,构成一个线性数组
case 2 和 case 3 包含case 1,最终结果只需要去 max(case 2, case 3) 即可。
class Solution:
# 打家劫舍1 代码
def rob1(self, nums: List[int]) -> int:
# 如果没有房屋,返回0
if len(nums) == 0:
return 0
# 如果有一间房屋,返回唯一金额
if len(nums) == 1:
return nums[0]
# 创建dp数组
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 - 2] + nums[i], dp[i - 1])
return dp[-1]
def rob(self, nums: List[int]) -> int:
# 如果没有房屋,返回0
if len(nums) == 0:
return 0
# 如果有一间房屋,返回唯一金额
if len(nums) == 1:
return nums[0]
# 不包括最后一个房间
nums1 = nums[:-1]
# 不包括第一个房间
nums2 = nums[1:]
result1 = self.rob1(nums1)
result2 = self.rob1(nums2)
result = max(result1, result2)
return result
三、337. 打家劫舍III
题目链接:337. 打家劫舍 III - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——337. 打家劫舍III
视频讲解:动态规划,房间连成树了,偷不偷呢?| LeetCode:337.打家劫舍3_哔哩哔哩_bilibili
树形动态规划六部曲:
1. 确定 dp 数组及下标含义:dp[ 0 ]表示不偷当前节点获得的最大金钱,dp[ 1 ]表示偷当前节点获得的最大金钱。
2. 确定递归函数参数和返回值;
3. 确定确定终止条件:
4. 确定遍历顺序:
5. 确定单层递归逻辑:
6. 举例推导dp数组。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def traversal(self, node):
# 确定终止条件,如果当前节点为空节点,不偷
if not node:
return (0, 0)
# 后序遍历
left = self.traversal(node.left)
right = self.traversal(node.right)
# 中,不偷当前节点,偷子节点
val_0 = max(left[0], left[1]) + max(right[0], right[1])
# 中,偷当前节点,不偷子节点
val_1 = node.val + left[0] + right[0]
return(val_0, val_1)
def rob(self, root: Optional[TreeNode]) -> int:
# 构建dp数组
dp = self.traversal(root)
return max(dp)