【算法训练记录——Day45】

news2024/11/16 7:32:09

Day45——动态规划Ⅶ

  • 1.leetcode19_打家劫舍
  • 2.leetcode213_打家劫舍Ⅱ
  • 3.leetcode337_打家劫舍Ⅲ

1.leetcode19_打家劫舍

在这里插入图片描述
思路:我的理解是不能出现连续两次偷窃,即
要么今晚不偷 dp[i] = dp[i-1];
要么今晚开干! dp[i] = dp[i-2] + nums[i];

怎么初始化: 从公式可知,至少初始化前两晚。dp[0] = nums[0] dp[1] = nums[1]

	int rob(vector<int>& nums) {
        vector<int> dp(nums.size(), 0);
        if(nums.size() < 2) return nums[0];
        if(nums.size() == 2) return max(nums[0], nums[1]);

        dp[0] = nums[0];
        dp[1] = nums[1];

        for(int i = 2; i < nums.size(); i++) {
            int tmp = 0;
            for(int j = 0; j < i-1; j++)
                tmp = max(tmp, dp[j]);
            dp[i] = max(dp[i-1], tmp + nums[i]);
        }

        return dp[nums.size()-1];
    }

看了下题解,思路有所开阔。我之前的假设是
要么今晚不偷 dp[i] = dp[i-1];
要么今晚开干! dp[i] = dp[i-2] + nums[i];
然后我在递推时发现dp[i-2]可以是i-2之前的最大的一次,因此每次循环都获取了一次最大值,但其实,我们可以直接给dp赋值时,就把这一步骤完成,例如dp[i]就是前i次的最大值
dp[0] = nums[0], dp[1] = max(nums[0], nums[1]);
这样我每次遍历dp[i]就是最大值,可以少一个 for 循环

	int rob(vector<int>& nums) {
        vector<int> dp(nums.size(), 0);
        if(nums.size() < 2) return nums[0];

        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);

        for(int i = 2; i < nums.size(); i++) {
            dp[i] = max(dp[i-1], dp[i-2] + nums[i]);
        }

        return dp[nums.size()-1];
    }

2.leetcode213_打家劫舍Ⅱ

在这里插入图片描述
思路:和上一题一样,只是多了首尾不能相接。偷是一个累加的过程
那就有两种偷法:1. 第一天开始偷,最后一天不偷
2. 第二天开始偷,最后一天可以偷
剩下跟上一个一样

    int rob(vector<int>& nums) {
		if(nums.size() == 1) return nums[0];

		int res1 = robRange(nums, 0, nums.size() - 2);
		int res2 = robRange(nums, 1, nums.size() - 1);

		return max(res1, res2);
	}
	
    int robRange(const vector<int>& nums, int start, int end) {
		if(start == end) return nums[start];

		vector<int> dp(nums.size(), 0);
		dp[start] = nums[start];
		dp[start + 1] = max(nums[start], nums[start + 1]);

		for(int i = start + 2; i <= end; i++) {
			dp[i] = max(dp[i-2] + nums[i], dp[i-1]);	
		}
		return dp[end];
	}

3.leetcode337_打家劫舍Ⅲ

在这里插入图片描述
在这里插入图片描述
记忆化递归:对于当前节点,有两个结果,一个是偷,并且下一次只能从孩子的孩子里偷;一个是当前不偷,从孩子节点里偷
即 dp[root] = dp[root->left ->children] + root->val;
dp[root] = dp[root->children]

	unordered_map<TreeNode* , int> umap; // 记录计算过的结果
public:
    int backtracking(TreeNode* root) {
        if(root == nullptr) return 0;

        if(umap[root]) {
            return umap[root];
        }

        if(root->left == nullptr && root->right == nullptr) {
            return root->val;
        }

        int tmpVal1 = root->val;
        if(root->left != nullptr) {
            tmpVal1 += backtracking(root->left->left);
            tmpVal1 += backtracking(root->left->right);
        }

        if(root->right != nullptr) {
            tmpVal1 += backtracking(root->right->left);
            tmpVal1 += backtracking(root->right->right);
        }

        int tmpVal2 = 0;
        tmpVal2 += backtracking(root->left);
        tmpVal2 += backtracking(root->right);

        umap[root] = max(tmpVal1, tmpVal2);

        return umap[root];
    }

    int rob(TreeNode* root) {
        return backtracking(root);
    }

二:动态规划
对于当前节点,存在偷或不偷两种情况;
所以dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。
若当前节点不偷, 则最大值为孩子节点偷与偷的最大值 dp[root, 0] = max(dp[root->left,0], dp[root->left,1]) + max(dp[root->right,0], dp[root->right,1])
若当前节点偷,那么孩子不能偷 dp[root, 1] = dp[root->left, 0] + dp[root->right, 0]
因为需要用到递归函数返回值,所以使用 后序遍历

	vector<int> robTree(TreeNode* root) {
        if(root == nullptr) return vector<int> {0, 0};

        vector<int> left = robTree(root->left);
        vector<int> right = robTree(root->right);

        int val1 = root->val + left[0] + right[0];
        int val2 = max(left[1], left[0]) + max(right[1], right[0]);

        // cout << val2 << " " << val1 << endl;
        return {val2, val1};
    }

    int rob(TreeNode* root) {
        // return backtracking(root);
        vector<int> res = robTree(root);
        return max(res[0], res[1]);
    }

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

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

相关文章

NVM 安装node报错 Could not retrieve https://nodejs.org/dist/latest/SHASUMS256.txt.

报错内容&#xff1a; Could not retrieve https://nodejs.org/dist/latest/SHASUMS256.txt. 解决这个办法需要修改nvm的淘宝镜像 在nvm的目录下编辑settings.txt 将下面内容&#xff1a; node_mirror:npm.taobao.org/mirrors/node/ npm_mirror:npm.taobao.org/mirrors/npm/…

酷柚易汛ERP再次迎来升级,八月重拳出击!

1、修复调拨单批量导入下载模版错误 2、修复添加门店选择地址详情报错 3、修复采购清单 关联其他支出单 跳转 之后审核 原采购清单 关联其他支出单消失问题 4、修复以销订购 填了了采购数量 仍然提示请填写本次采购数量问题 5、修复应付款/收款明细表 单据编号是 核销单/其他…

Linux第八节 - make / mikefile

一、补充与复习 Linux在运行可执行程序的时候&#xff0c;有两种运行方式&#xff1a; ./mytest &#xff08;表示当前路径下的可执行程序 - 用/分隔开&#xff09; /home/shy/108/lesson8/mytest &#xff08;也可以运行程序&#xff0c;但是是在绝对路径下&#xff01;&…

图观 | 嬴图GraphRAG在博物馆文物馆藏中的应用探讨

图数据库技术是AI走向强人工智能的必经之路和重器&#xff01;因为图数据库&#xff08;含知识图谱&#xff09;最大限度还原&#xff08;模拟&#xff09;了人的思维和思考方式。 —— 摘自孙宇熙《图数据库原理、架构与应用》 前言&#xff1a; 博物馆文物馆藏管理和观众服务…

基于内地城市生活垃圾收运场景的路线规划算法

基于混合遗传算法和模拟退火算法的优化垃圾收集路线规划 摘要 本论文提出了一种基于混合遗传算法&#xff08;GA&#xff09;和模拟退火算法&#xff08;SA&#xff09;的创新路线规划方法&#xff0c;旨在优化内地城市的生活垃圾收集效率。算法结合了遗传算法的全局搜索能力…

中证500etf期权合约一手多少钱?

中证500etf期权合约一手需要的资金取决于多个因素&#xff0c;比如做一手需要几十块钱到几百块钱不等&#xff0c;不过买卖中证500etf期权合约一手多少钱&#xff0c;也是包括期权的执行价格、权利金、保证金要求等。下文为大家介绍中证500etf期权合约一手多少钱&#xff1f;本…

.\venv\Scripts\activate : 无法加载文件 E:\,因为在此系统上禁止运行脚本。

问题描述&#xff1a; 问题原因&#xff1a; Windows PowerShell 的执行策略用于控制脚本的运行权限和安全性。 以下是几种常见的执行策略及其特点&#xff1a; AllSigned&#xff1a;只允许运行经过数字签名的脚本。这意味着无论是本地创建的还是从网络获取的脚本&#xff0…

如何设计一个高性能的分布式系统?

本文讨论的主题是高性能&#xff0c;主要思路是围绕快展开&#xff0c;这么设计为什么会快&#xff1f; 文章目录 架构设计&#xff1a;微服务架构负载均衡数据一致性方案选择容错处理&#xff1a;双机互备消息队列缓存总结 架构设计&#xff1a;微服务架构 第一个设计是应用…

“再来一单“业务功能开发

文章目录 概要整体架构流程技术细节小结 概要 再来一单”功能常见于餐饮、零售、外卖等行业&#xff0c;主要目的是为了简化用户的重复购买流程&#xff0c;提高用户体验和效率。 需求分析以及接口设计 再来一单就是将原订单中的商品重新加入到购物车中,所以本质上是"增…

人工智能助力芯片半导体发展,开拓芯片设计技术新趋势

微型硅片上可以容纳多少个晶体管&#xff1f;这些晶体管是构成世界各地技术的集成电路&#xff08;IC&#xff09;的基础。1971年&#xff0c;第一款微处理器集成有2,300个晶体管&#xff0c;而如今的硅片上却超过了1000亿个晶体管。在摩尔定律失效之前&#xff0c;每两年晶体管…

10、billu-b0x2

难度 中 目标 root权限 首先确定靶机ip地址 netdiscover -i eth0 -r 192.168.189.0/24 kali 192.168.189.58 靶机 192.168.189.184 信息收集端口扫描 看到一个80和8080&#xff0c;先重点摸一下网站的内容 然后看到信息里有个robots.txt 首先就去访问一下 看到有许多不允许…

高频JMeter软件测试面试题

近期&#xff0c;有很多粉丝在催更关于Jmeter的面试题&#xff0c;索性抽空整理了一波&#xff0c;以下是一些高频JMeter面试题&#xff0c;拿走不谢~ 一、JMeter的工作原理 JMeter就像一群将请求发送到目标服务器的用户一样&#xff0c;它收集来自目标服务器的响应以及其他统计…

传统产品经理VS现在AI产品经理,你要学习的太多了,超详细收藏我这一篇就够了

传统产品经理想要转行成为AI产品经理&#xff0c;需要经历一系列的学习和实践过程。下面是一份详细的学习路线图&#xff0c;旨在帮助你顺利转型。 学习路线图 了解AI基础知识 AI概览&#xff1a;阅读《人工智能&#xff1a;一种现代的方法》这样的书籍&#xff0c;以获得对AI…

初谈Linux多线程--线程控制

文章目录 线程的概述理解线程Linux中的线程重新理解的进程Windows的线程线程的优点线程的缺点理解线程调度成本低 进程VS线程 线程控制创建线程等待线程线程函数传参线程的返回值新线程的返回值新线程返回值错误返回值为类对象 创建多线程线程的终止线程的分离pthread_detach 线…

AIExpo2024奖项申报正式启动,三大奖项为你闪耀

由新一代人工智能产业技术创新战略联盟、苏州市人工智能协同创新中心联合主办&#xff0c;苏州启智创新科技有限公司、苏州工业园区科技发展有限公司共同承办的第六届全球人工智能产品应用博览会&#xff08;以下简称“智博会”&#xff09;将于2024年9月11-12日在苏州国际博览…

二叉搜索树,Map,Set,LeetCode刷题

二叉搜索树&#xff0c;Map&#xff0c;Set 1. 二叉搜索树2. 二叉搜索树的模拟实现1.1 插入操作1.2 查找操作1.3 删除操作 3. 二叉搜索树时间复杂度分析4. TreeMap和TreeSet5. Map5.1 Map的常用方法5.2 Map.Entry<K,V> 6. Set6.1 Set的常用方法 LeetCode刷题1. 二叉搜索树…

Total Eclipse 挑战赛:在以太坊首个 SVM L2 上开发应用

摘要&#xff1a;Eclipse 基金会宣布了其首届黑客马拉松计划&#xff0c;即"The Total Eclipse Challenge"&#xff0c;作为一场独一无二的黑客松活动 &#xff0c;邀请了优秀的开发者们在链上开发创新的应用。 "The Total Eclipse 挑战赛" 是一项为期两周…

如何更好地做出判断?

笛卡尔有句名言&#xff1a;无法下判断的人&#xff0c;不是欲望太奢侈&#xff0c;就是觉悟还不够。 这里说的判断&#xff0c;其实也就是选择。我们人生面临着各种维度的选择&#xff0c;大到人生方向&#xff0c;小到一顿饭吃什么&#xff0c;可以说&#xff0c;选择伴随着我…

全志T113i移植LAN8720指南

1、根据硬件修改设备树 gmac0_pins_a: gmac0 {allwinner,pins "PG0", "PG1", "PG2", "PG3", "PG4","PG5", "PG11", "PG12", "PG13", "PG14", "PG15";allwin…

vue3+TS+nest+mysql实现网站访问统计系统

网站采用了vue3tsnestmysql的技术选型&#xff0c;目前初步实现第一版开发 访问地址&#xff1a;点我进入网站 网站访问统计 主要通过插入script来调用上传接口来实现数据统计,目前仅存储了用户的ip和访问时间&#xff0c;后期也可根据ip来获取用户的城市信息 async pageUplo…