代码随想录算法训练营第四十七天|198. 打家劫舍、213. 打家劫舍II、337. 打家劫舍III

LeetCode 198. 打家劫舍
题目链接:198. 打家劫舍 - 力扣(LeetCode)代码随想录算法训练营第四十七天|198. 打家劫舍、213. 打家劫舍II、337. 打家劫舍III_第1张图片

第一次打家劫舍,来个简单一些的,无非就是偷了当前这家偷不了下一家,因此dp[n]代表,偷前n家的时候所能偷到的最高金额,递推公式是dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])

每道题都要考虑dp五步:

1)确定dp数组下标与值的关系:偷前n家的时候所能偷到的最高金额

2)确定递推公式:dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])

3)确定初始值:dp[0]为0,dp[1]为nums[0]

4)确定遍历的数:边界为2,到n

5)带入验证一下

代码:

#python  打家劫舍I  一维DP
class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0 for _ in range(n)]
        dp[0] = nums[0]
        for i in range(1, n):
            if i == 1:
                dp[i] = max(nums[i - 1], nums[i])
            else:
                dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])
        return dp[-1]

LeetCode 213. 打家劫舍II
题目链接:213. 打家劫舍 II - 力扣(LeetCode)代码随想录算法训练营第四十七天|198. 打家劫舍、213. 打家劫舍II、337. 打家劫舍III_第2张图片

第二次打家劫舍,在上次的基础上,头尾相连了,因此偷了最后一家就没法投第一家了,因此我们分类讨论,分别讨论[0,n - 1]与[1, n]两个区间的最大情况;同样的,dp[n]代表,偷前n家的时候所能偷到的最高金额,递推公式是dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])

每道题都要考虑dp五步:

1)确定dp数组下标与值的关系:偷前n家的时候所能偷到的最高金额

2)确定递推公式:dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])

3)确定初始值:dp[0]为0,dp[1]为nums[0]

4)确定遍历的数:边界为2,到n

5)带入验证一下

代码:

#python  打家劫舍II
from typing import List

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 0:  //分别总体讨论特殊情况
            return 0
        if n == 1:
            return nums[0]
        if n == 2:
            return max(nums[0], nums[1])
        
        def rob_helper(nums):     //定义一个函数实现打家劫舍I的功能
            n = len(nums)
            dp = [0 for _ in range(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]
        
        return max(rob_helper(nums[1:]), rob_helper(nums[:-1]))  //返回俩区间的最大值

LeetCode 337. 打家劫舍III
题目链接:337. 打家劫舍 III - 力扣(LeetCode)代码随想录算法训练营第四十七天|198. 打家劫舍、213. 打家劫舍II、337. 打家劫舍III_第3张图片

第三次打家劫舍,这次是真牛逼了,小偷懂能发现二叉树了,程序员下岗再就业了属于是0.0

按照来想,无非就是选与不选当前节点,同时使用递归来实现DP.

每道题都要考虑dp五步:

1)确定dp数组下标与值的关系:偷前n家的时候所能偷到的最高金额

2)确定递推公式:dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])

3)确定初始值:dp[0]为0,dp[1]为nums[0]

4)确定遍历的数:边界为2,到n

5)带入验证一下

代码:

#python  //打家劫舍III
# 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 rob(self, root: Optional[TreeNode]) -> int:
        dp = self.traveral(root)
        return max(dp)
    
    def traveral(self, node):
        if not node:
            return 0, 0
        
        left = self.traveral(node.left)  //递归左子树
        right = self.traveral(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)

你可能感兴趣的:(算法)