算法打卡day41

news2024/11/20 15:30:40

今日任务:

1)198.打家劫舍

2)213.打家劫舍II

3)337.打家劫舍III

4)复习day16

198.打家劫舍

题目链接:198. 打家劫舍 - 力扣(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。

提示:
0 <= nums.length <= 100
0 <= nums[i] <= 400

文章讲解:代码随想录 (programmercarl.com)

视频讲解:动态规划,偷不偷这个房间呢?| LeetCode:198.打家劫舍哔哩哔哩bilibili

思路:

这个问题是一个典型的动态规划问题。我们可以使用动态规划来解决这个问题,其中关键是定义状态和状态转移方程。

状态定义:
定义一个数组 dp,其中 dp[i] 表示偷窃前 i 个房屋所能获取的最高金额。

状态转移方程:
考虑偷窃第 i 个房屋,有两种情况:

  1. 偷窃第 i 个房屋:如果偷窃第 i 个房屋,则不能偷窃第 i-1 个房屋,因此偷窃金额为 nums[i] + dp[i-2]
  2. 不偷窃第 i 个房屋:如果不偷窃第 i 个房屋,则偷窃金额与偷窃前 i-1 个房屋所能获取的最高金额相同,即 dp[i-1]

因此,动态转移方程为:

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

初始状态:

  • 第一个房屋只有一间,因此偷窃它即可,即 dp[0] = nums[0]
  • 第二个房屋偷窃与不偷窃中选择金额较大的方案,即 dp[1] = max(nums[0], nums[1])

返回结果:
最终结果为 dp[-1],表示偷窃前所有房屋所能获取的最高金额。

class Solution:
    def rob(self, nums: List[int]) -> int:
        if not nums:  # 如果没有房屋,返回0
            return 0
        if len(nums) == 1:  # 如果只有一个房屋,返回其金额
            return nums[0]

        # 定义动态规划数组,dp[i] 表示偷窃前 i 个房屋所能获取的最高金额
        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 - 1], dp[i - 2] + nums[i])

        return dp[-1]

213.打家劫舍II

题目链接:213. 打家劫舍 II - 力扣(LeetCode)

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。

示例 1:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4 。

示例 3:
输入:nums = [0]
输出:0

提示:
1 <= nums.length <= 100
0 <= nums[i] <= 1000

文章讲解:代码随想录 (programmercarl.com)

视频讲解:动态规划,房间连成环了那还偷不偷呢?| LeetCode:213.打家劫舍II哔哩哔哩bilibili

思路:

这个问题与之前的类似,但有一个额外的条件:房屋围成一圈。因此,我们需要特殊处理这个情况。

我们可以将这个问题拆分成两个子问题:

  1. 偷窃第一个房屋,不偷窃最后一个房屋。
  2. 偷窃最后一个房屋,不偷窃第一个房屋。

然后,我们可以使用动态规划来解决这两个子问题,最后取两个子问题中的最大值作为结果。

具体的动态规划解决方案如下:

  1. 对于第一个子问题,我们可以使用与之前类似的动态规划方法来解决。假设 dp1[i] 表示偷窃前 i 个房屋(第一个房屋被偷窃)所能获取的最高金额,则有以下状态转移方程:

    dp1[i] = max(dp1[i-1], dp1[i-2] + nums[i]) 其中 dp1[0] = nums[0],dp1[1] = max(nums[0], nums[1])
  2. 对于第二个子问题,同样使用动态规划方法。假设 dp2[i] 表示偷窃前 i 个房屋(最后一个房屋被偷窃)所能获取的最高金额,则有以下状态转移方程:

    dp2[i] = max(dp2[i-1], dp2[i-2] + nums[i]) 其中 dp2[0] = 0dp2[1] = nums[1]

最终,我们可以将两个子问题的最终结果进行比较,取其中较大的值作为最终结果。

class Solution:
    def rob(self, nums: List[int]) -> int:
        if not nums:  # 如果没有房屋,返回0
            return 0
        if len(nums) == 1:  # 如果只有一个房屋,返回其金额
            return nums[0]

        # 计算偷窃第一个房屋,不偷窃最后一个房屋的最高金额
        res1 = self.rob_range(nums,0,len(nums)-2)
        # 计算偷窃最后一个房屋,不偷窃第一个房屋的最高金额
        res2 = self.rob_range(nums,1,len(nums)-1)

        # 取两个子问题的最大值作为最终结果
        return max(res1,res2)


    # 动态规划解决子问题
    def rob_range(self,nums: List[int], start: int, end: int) -> int:
        if end == start:
            return nums[start]

        # 创建一个数组用于存储每个房屋偷窃时的最高金额
        dp = [0]*(end-start+1)
        # 初始化前两个房屋的最高金额
        dp[0] = nums[start]
        dp[1] = max(nums[start],nums[start+1])

        for i in range(2, end - start + 1):
            # 在偷窃当前房屋和不偷窃当前房屋之间选择金额较大的方案
            dp[i] = max(dp[i-1],dp[i-2]+nums[start+i])

        return dp[-1]

337.打家劫舍III

题目链接:337. 打家劫舍 III - 力扣(LeetCode)

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:
输入: root = [3,2,3,null,3,null,1]
输出: 7
解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7

示例 2:
输入: root = [3,4,5,1,3,null,1]
输出: 9
解释: 小偷一晚能够盗取的最高金额 4 + 5 = 9

提示:
树的节点数在 [1, 104] 范围内
0 <= Node.val <= 104

文章讲解:代码随想录 (programmercarl.com)

视频讲解:动态规划,房间连成树了,偷不偷呢?| LeetCode:337.打家劫舍3哔哩哔哩bilibili

思路:

在这个问题中,我们有一棵二叉树,表示小偷可以盗取的房屋。每个节点表示一个房屋,节点的值表示房屋内的现金。树中的相邻节点表示相邻的房屋,如果相邻的房屋在同一晚上被打劫,系统会自动报警。

我们的目标是计算在不触发警报的情况下,小偷一晚能够盗取的最高金额。

解决这个问题的一种方法是使用动态规划。我们可以定义一个递归函数rob(root),其中 root 是当前节点。对于每个节点,我们有两种选择:

  1. 盗取当前节点和其孙子节点的价值,然后考虑其孙子节点的左右孩子。
  2. 不盗取当前节点,而是考虑其两个子节点。

我们可以通过递归地计算这两种选择来获得最大金额。但是,这样的方法可能会导致大量的重复计算。为了避免这种情况,我们可以使用记忆化搜索或动态规划来优化递归解法。在动态规划方法中,我们可以定义一个状态数组 dp,其中 dp[node] 表示盗取以 node 为根节点的子树所能获得的最大金额。然后,我们可以根据状态转移方程来计算 dp[node]。

具体地,对于每个节点 node,我们有两种选择:

  1. 如果我们盗取了当前节点 node,则不能盗取其孩子节点。因此,最大金额为 node.val + dp[node.left.left] + dp[node.left.right] + dp[node.right.left] + dp[node.right.right]。
  2. 如果我们不盗取当前节点 node,则可以选择盗取其左孩子和右孩子。因此,最大金额为 dp[node.left] + dp[node.right]。

最后,我们返回根节点的最大金额,即 dp[root]。

这样,我们可以通过动态规划来高效地解决这个问题,确保小偷在不触发警报的情况下,一晚能够盗取的最高金额。

# 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: TreeNode) -> int:
        # 调用辅助函数并返回根节点的最大金额
        return max(self.dfs(root))

    # 定义一个辅助函数来计算盗取以root为根节点的子树所能获得的最大金额
    def dfs(self, node):
        if not node:
            return 0, 0  # 返回不盗取当前节点和盗取当前节点的最大金额

        # 递归计算左右子树的最大金额
        left_no_rob, left_rob = self.dfs(node.left)
        right_no_rob, right_rob = self.dfs(node.right)

        # 不盗取当前节点时,可以选择盗取左右子树的根节点或者不盗取左右子树的根节点
        no_rob = max(left_no_rob, left_rob) + max(right_no_rob, right_rob)

        # 盗取当前节点时,不能盗取左右子树的根节点
        rob = node.val + left_no_rob + right_no_rob

        return no_rob, rob


root = TreeNode(3,2,3)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.right = TreeNode(3)
root.right.right = TreeNode(1)

obj = Solution()

print(obj.rob(root))

感想:这题有点变化,用到了二叉树,这里要先算子节点的最大值,再算父节点,所以这题要采用后序遍历。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1641833.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AttributeError: module ‘numpy‘ has no attribute ‘int‘.

问题描述 复现代码过程中遇到错误&#xff1a;AttributeError: module numpy has no attribute int. 错误代码行&#xff1a; self.sf np.int(data[sf][0,...].squeeze().cpu().numpy()) # scale factor 解决方案 这是因为在Numpy 1.2.0版本中就已经弃用了这个用法&#x…

探索动态内存开辟的奥秘

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 前言 开始之前&#xff0c;我们先来了解一下C/C中程序内存区域划分。 在C/C程序中&#xff0c;内存区域通常被划分为以下几个部分&#xff1a; 1.栈&…

【基础算法总结】滑动窗口一

滑动窗口 1.长度最小的字数组2.无重复字符的最长子串3.最大连续1的个数 III4.将 x 减到 0 的最小操作数 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&…

软件测试(实验五)——Jmeter的使用

目录 实验目的 一、使用JMeter演示取样器、监听器、配置元件、断言的使用&#xff1b; 1、取样器 2、监听器 3、配置元件的使用 ① 用户定义的变量 ②HTTP信息头管理器 ③HTTP请求默认值 ④CSV数据文件设置 4、断言 ①响应断言 ②JSON断言 ③断言持续时间 二、使用…

普通二维码打开微信小程序并且传递参数

实现方法&#xff1a; 【1】确保有一个企业级别的认证过的微信小程序 【2】有一个https并且备案过的域名 【3】进入微信后台“开发”-“开发设置”-“扫普通链接二维码打开小程序”-“添加” 官方文档&#xff1a;https://developers.weixin.qq.com/miniprogram/introduction/q…

C语言实验-学生信息管理系统

按以下菜单界面编写学生信息管理系统&#xff1b; 1&#xff09;录入学生信息首先输入学生人数&#xff0c;然后根据学生人数开辟动态数组&#xff1b; 2&#xff09;学生信息包括学号、姓名、性别、三门课成绩、总分&#xff1b;其中学号、姓名、 性别、三门课成绩是需要从键盘…

YOLO自研模块:多尺度轻量化卷积模块

目录 一、原理 二、代码 三、配置文件 一、原理 不同大小的卷积核,提取目标特征的特征尺度不同,所以通过使用不同大小卷积核的卷积来提取特征就可以保证获取到目标的多尺度特征。 借鉴YOLOv8中,将通道数进行划分的操作,在卷积的输入过程中为了减小参数量,将输入通道数…

截图时,VSCode屏幕泛白

问题如图所示&#xff1a; 放弃前摇&#xff0c;直接给出解决方案&#xff1a;换个主题即可。 实测&#xff0c;Light Modern 的色域正常&#xff0c;其他的没有经过测试。 出现这个问题的原因&#xff0c;大概率就是色彩空间不匹配。 HDR 内容是为了在支持 HDR 的显示设备上展…

H3C MSTP 实验

H3C MSTP 实验 实验拓扑 ​​ 实验需求 所有交换机上创建 Vlan10&#xff0c;Vlan20&#xff0c;Vlan30 和 Vlan40所有交换机之间的端口配置为 Trunk&#xff0c;并放行相关 VLAN按照图示分区域配置 MSTP&#xff0c;并配置主备根网桥 实验步骤 VLAN基础配置&#xff08;…

C++ 多态(二)

四、多态纯虚函数 纯虚函数是在C中用来定义抽象类的一种特殊函数。纯虚函数没有具体的实现&#xff0c;只有函数声明&#xff0c;它的作用是为派生类提供一个接口&#xff0c;让派生类必须实现这个函数。如果一个类中包含了纯虚函数&#xff0c;那么这个类就是抽象类&#xff…

史上最复杂的探测器嫦娥六号,如何采取人类首份月背样品? | 最新快讯

作者&#xff1a;LM-51D-YZ4D2&#xff0c;航天爱好者 今天&#xff0c;长征五号遥八火箭即将从海南文昌航天发射场点火起飞&#xff0c;把嫦娥六号探测器送入预定轨道。作为嫦娥五号的备份器&#xff0c;嫦娥六号继承了嫦娥五号的结构&#xff0c;又针对月球背面着陆进行了优化…

6.【Orangepi Zero2】localtime、asctime函数

【Orangepi Zero2】localtime、asctime函数 localtime、asctime localtime、asctime #include <time.h>struct tm *localtime(const time_t *timep); char *asctime(const struct tm *tm);localtime() 是 把从1970-1-1零点零分到当前时间系统所偏移的秒数时间转换为本地…

批量视频剪辑新选择:一键式按照指定秒数分割视频并轻松提取视频中的音频,让视频处理更高效!

是否经常为大量的视频剪辑工作感到头疼&#xff1f;还在一个个手动分割、提取音频吗&#xff1f;现在&#xff0c;我们为你带来了一款全新的视频批量剪辑神器&#xff0c;让你轻松应对各种视频处理需求&#xff01; 首先&#xff0c;进入媒体梦工厂的主页面&#xff0c;并在板…

后台架构总结

前言 疫情三年&#xff0c;全国各地的健康码成为了每个人的重要生活组成部分。虽然过去一年&#xff0c;但是回想起来任然历历在目。 今天我就通过当时基于小程序的健康码架构&#xff0c;来给大家讲一下如何基于java&#xff0c;springboot等技术来快速搭建一个后台业务系统…

freeRTOS任务通知(1-17)

任务通知简介&#xff1a; def&#xff1a; 任务通知是用来通知任务的&#xff0c;任务控制块中的结构体成员变量ulNotifiedValue就是这个通知值。 任务通知的内存消耗比较小 1&#xff1a; 使用队列&#xff0c;信号量&#xff0c;时间标志组都需要另外创建结构体&#xff…

C++设计模式-创建型设计模式

设计模式 设计模式是什么 设计模式是指在软件开发中&#xff0c;经过验证的&#xff0c;用于解决在特定环境下&#xff0c;重复出现的&#xff0c;特定问题的解决方案&#xff1b;其实就是解决问题的固定套路。但是要慎用设计模式&#xff0c;有一定的工程代码量之后用它比较…

ue引擎游戏开发笔记(29)——实现第三人称角色随手柄力度进行移动

1.需求分析 角色可以随手柄力量大小进行走路和跑步&#xff0c;不动时保持角色停顿。 2.操作实现 1.思路&#xff1a;通过动画蓝图和动画混合实现角色移动和输入的联系。 2.建立动画蓝图和混合空间&#xff1a; 3.在混合空间中对角色移动进行编辑&#xff1a; 4.在蓝图中设定变…

HTML_CSS学习:浮动

一、浮动简介 相关代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>浮动_简介</title><style>div{width: 600px;height: 400px;background-color: #1c80d9;}img{float:…

Java进阶【十三期】:【异常处理】 (抛出捕获异常、自定义异常处理)、处理异常的几种方式 【(File】文件路径操作、File文件处理的综合练习

文章目录 Java进阶【十三期】&#xff1a;异常处理一、异常基本介绍二、编译异常和运行异常三、总结 异常的作用异常的处理方式一、JVM默认的处理方式二、自己处理异常自己 处理的问题 三、总结 Throwable 成员方法抛出异常总结 异常练习自定义异常 FileFile 三个 构造方法File…

【SSM进阶学习系列丨分页篇】PageHelper 分页插件导入集成实践

文章目录 一、说明什么是分页PageHelper介绍 二、导入依赖三、集成Spring框架中四、编写Service五、编写Controller六、编写queryAllByPage页面展示数据 一、说明 什么是分页 ​ 针对分页&#xff0c;使用的是PageHelper分页插件&#xff0c;版本使用的是5.1.8 。 ​ 参考文档…