经典动态规划:打家劫舍系列问题

article/2025/9/12 18:09:47

打家劫舍系列总共有三道,难度设计非常合理,层层递进。第一道是比较标准的动态规划问题,而第二道融入了环形数组的条件,第三道更绝,让盗贼在二叉树上打劫.
House Robber | 在这里插入图片描述

public int rob(int[] nums);

题目很容易理解,而且动态规划的特征很明显。解决动态规划问题就是找「状态」和「选择」。
假想你就是这个专业强盗,从左到右走过这一排房子,在每间房子前都有两种选择:抢或者不抢。
如果你抢了这间房子,那么你肯定不能抢相邻的下一间房子了,只能从下下间房子开始做选择。
如果你不抢这间房子,那么你可以走到下一间房子前,继续做选择。
当你走过了最后一间房子后,你就没得抢了,能抢到的钱显然是 0(base case)。
以上的逻辑很简单吧,其实已经明确了「状态」和「选择」:你面前房子的索引就是状态,抢和不抢就是选择。
状态表示:dp[i][0/1]表示第i个房子偷或不偷的最高金额
初始边界:dp[0][] = {0,0}
转移方程:
当前房子不偷:dp[i][1] = dp[i-1][0] + nums[i]
当前房子偷: dp[i][0] = max{dp[i-1][0],dp[i-1][1]}

int rob(vector<int>& nums) {vector<vector<int>> dp(nums.size()+1,vector<int>(2,0));for(int i = 1; i <= nums.size(); i++){dp[i][0] = max(dp[i-1][1],dp[i-1][0]);dp[i][1] = dp[i-1][0] + nums[i-1];}return max(dp[nums.size()][0],dp[nums.size()][1]);
}

间复杂度:O(N)
空间复杂度:O(N)
优化:用四个变量表示代替上面的状态

int rob(vector<int>& nums) {int n = nums.size();int last_0 = 0, last_1 = 0, curr_0 = 0, curr_1 = 0;for(int i = 0; i < nums.size(); i++){curr_0 = max(last_0, last_1);curr_1 = last_0 + nums[i];last_0 = curr_0;last_1 = curr_1;}return max(curr_0, curr_1);
}

时间复杂度:O(N)
空间复杂度:O(1)

打家劫舍II(动态规划)
在这里插入图片描述
这道题目和第一道描述基本一样,强盗依然不能抢劫相邻的房子,输入依然是一个数组,但是告诉你这些房子不是一排,而是围成了一个圈。

也就是说,现在第一间房子和最后一间房子也相当于是相邻的,不能同时抢。比如说输入数组 nums=[2,3,2],算法返回的结果应该是 3 而不是 4,因为开头和结尾不能同时被抢。
那么就会有这两种情况:
第一间房子抢的化最后一间房子就不能抢
最后一间房子抢的话第一间房子就不能抢
所以结合打家劫舍I我们可以实现这样种情况,然后返回这两种情况的最大值就是答案。

    int rob(vector<int>& nums) {if(nums.size() == 0) return 0;if(nums.size() == 1) return nums[0];// 第一间房子抢的化最后一间房子就不能抢vector<int> nums1(nums.begin()+1,nums.end());// 最后一间房子抢的话第一间房子就不能抢vector<int> nums2(nums.begin(),nums.end()-1);// 取两者最大值return max(rob2(nums1),rob2(nums2));}int rob2(vector<int>& nums) {int pre = 0,curr = 0;for(int i = 0; i < nums.size(); i++){int tmp = curr;curr = max(curr,pre + nums[i]);pre = tmp;}return curr;}

打家劫舍III(树型DP)
在这里插入图片描述
状态转移方程:
当前房子偷 = 左房子不偷 + 右房子不偷 + 当前房子的钱
当前房子不偷 = max(左房子不偷,左房子偷) + max(右房子不偷,右房子偷)

函数maxPrifox:返回的是偷和不偷的最优策略对应的结果值

    struct data{int y; // 偷int n; // 不偷};int rob(TreeNode* root) {if(!root) return 0;data rs =  maxPrifox(root);return max(rs.y, rs.n);}data maxPrifox(TreeNode* root){if(!root) return {0, 0};// 1. 拿到左房子的所有状态信息data le = maxPrifox(root->left);// 2. 拿到右房子的所有状态信息data ri = maxPrifox(root->right);data rs;// 3. 当前房子偷 = 左房子不偷 + 右房子不偷 + 当前房子的钱rs.y = le.n + ri.n + root->val;// 4. 当前房子不偷 = max(左房子不偷,左房子偷) + max(右房子不偷,右房子偷)rs.n = max(ri.y, ri.n) + max(le.y, le.n);return rs;}

http://chatgpt.dhexx.cn/article/RCZnoyL7.shtml

相关文章

【算法】动态规划(三)——打家劫舍系列问题

目录 一、前言 二、打家劫舍 &#xff08;1&#xff09;198. 打家劫舍Ⅰ • 整体代码&#xff1a; &#xff08;2&#xff09;213. 打家劫舍 II • 题目分析 • 整体代码&#xff1a; &#xff08;3&#xff09;337. 打家劫舍Ⅲ • 思路分析 • 整体代码&#xff1a; 三、补充知…

动态规划之打家劫舍系列

前言 打家劫舍问题是一种非常经典的有限制条件的动态规划问题&#xff0c;按理说&#xff0c;不是一种特殊的类型&#xff0c;但是因为力扣上纯纯的出了三道题&#xff08;1&#xff0c;2&#xff0c;3&#xff09;来考察&#xff0c;题目的难度是依次递进的&#xff0c;还结合…

动态规划之打家劫舍

动态规划之打家劫舍 文章目录 动态规划之打家劫舍1. "198. 打家劫舍"2. "198. 打家劫舍&#xff08;变种&#xff1a;输出路径&#xff09;"3. "213. 打家劫舍 II"4. "337. 打家劫舍 III" 1. “198. 打家劫舍” dp数组定义&#xff1a…

oracle 根据部分字段去重

问题&#xff1a;在oracle中使用group by分组&#xff0c;group by子句中必须包含所有的select中的字段和order by子句中的字段。 在不使用group by子句的情况下&#xff0c;进行分组。&#xff08;根据部分字段分组&#xff09; over()分析函数 原sql SELECTIM. ID mediaGrou…

oracle字段去重查询,oracle怎么去重查询

oracle去重查询的方法是&#xff1a; oracle 数据库多字段去重 方法介绍&#xff1a;distinct 关键字、group by 、row_number ()over(partition by 列 order by 列 desc) 我的需求是&#xff1a;根据某几列去重 查询出去重后的全部信息。最后我选择的是第三种方法。 我的想法&…

oracle 数据去重方法

1. 创建表&#xff1a; -- Create table create table TEST_USER (user_id NUMBER(3),user_name VARCHAR2(20),user_age NUMBER(3) ) tablespace GUAN_TABLESPACEpctfree 10initrans 1maxtrans 255storage(initial 64Knext 1Mminextents 1maxextents unlimited);--测试数据…

oracle 字符串去重

select regexp_replace(1,1,3,5,5, ([^,])(,\1)*(,|$), \1\3) from dual;注意&#xff1a; 但是&#xff0c;这个去重&#xff0c;必须建立在排序的基础上&#xff0c;如果listagg拼接出来的数值像 a, b, a, c 这时候&#xff0c;该正则就会失效。

MYSQL/ORACLE多字段去重-根据某字段去重

通过百度上的答案多数无效 自己搞了个 使用oracle row_number()函数&#xff0c;给每个同名的加一个序号&#xff0c;最后筛选第n个想同的即可 oracle与mysql不同 1.oracel 多字段distinct(字段名去重) group by去重失效 可以用row_number() over(partition) 给同名列加个序号…

Oracle 数据去重

在Oracle数据库中删除重复数据 一&#xff0c;查询及删除重复记录的SQL语句 Person01表&#xff1a; 1. 查询表中多余的重复数据&#xff0c;根据ID字段来判断是否重复 SELECT * FROM PERSON01 WHERE ID IN (SELECT ID FROM PERSON01 GROUP BY ID HAVING COUNT(ID) > 1)…

Oracle根据多列去重

&#xff08;1&#xff09;distinct 关键词 distinct用于返回唯一不同的值&#xff0c;可作用于单列和多列 但必须将其放在开头&#xff0c;否则会提示错误 而若在其后添加多个变量名&#xff0c;则返回的将是这多个变量名不同时重复的列&#xff0c;因而使用distinct筛选某…

oracle 数据库去重查询

oracle数据库中有如下一张表&#xff0c;包含id,loginid,name,researchtime等字段&#xff0c;其中name字段中的数据有重复&#xff0c;查询数据时要重复数据只取一条&#xff0c;利用row_number ()over(partition by 列 order by 列 desc)方法实现 1:select a.,row_number() o…

oracle去重函数

1、distinct &#xff08;1&#xff09;、常用的distinct select distinct column from table; &#xff08;2&#xff09;、统计去重后数量 select count(distinct column) from table;–查去重后数量 &#xff08;3&#xff09;、distinct必须放在开头 select id, distinct n…

oracle 数据库 去重查询

oracle 数据库多字段去重 方法介绍&#xff1a;distinct 关键字、group by 、row_number ()over(partition by 列 order by 列 desc) 我的需求是&#xff1a;根据某几列去重 查询出去重后的全部信息。最后我选择的是第三种方法。 我的想法&#xff1a;我想找出一种更简单的方…

Oracle实现去重的两种方式总结

业务场景 需要查询某数据&#xff0c;由于需要三张表关联查询&#xff0c;查询结果如下&#xff1a; 原始SQL语句 SELECT D.ORDER_NUM AS "申请单号" ,D.CREATE_TIME ,D.EMP_NAME AS "申请人",(SELECT extractvalue(t1.row_data,/root/row/FI13_wasteNam…

mysql默认密码的查找与修改

注&#xff1a;此方法仅可用于初始安装数据库或学习时使用&#xff0c;在实际生产中会使所有数据库文件删除&#xff0c;故应先提前备份相关重要数据&#xff0c;以免造成不必要的损失&#xff0c;请谨慎使用。 若使用mysqld –initialize初始化mysql数据库&#xff0c;会产生一…

rpm安装mysql后密码_CentOs安装Mysql和配置初始密码

装载自&#xff1a;https://www.cnblogs.com/FlyingPuPu/p/7783735.html 一、Mysql下载安装 使用上传命令上传至/home目录&#xff0c;如&#xff1a;rz命令(yum install -y lrzsz) 添加mysql仓库(-Uvh后面接的为你下载的rpm文件名) sudo rpm -Uvh mysql57-community-release-e…

MySQL初始密码的查看

问题&#xff1a;在安装MySQL过程中&#xff0c;以管理员身份运行cmd后进入MySQL的bin目录&#xff0c;然后输入命令“mysqld --initialize”后没有显示初始密码&#xff0c;没办法进行后续的登录怎么办&#xff1f; 1.打开你的MySQL的安装目录下的data文件夹&#xff08;就是…

如何找到mysql的初始密码_如何查看mysql的初始密码

如何查看mysql的初始密码 发布时间:2020-08-26 11:50:11 来源:亿速云 阅读:95 作者:Leah 今天就跟大家聊聊有关如何查看mysql的初始密码,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 查看mysql的初始密码的…

[mysql]linux服务器mysql默认密码查看

通过 cat /var/log/mysqld.log | grep password 命令查看数据库的密码

centos查看mysql默认密码和修改密码

1、查看mysql默认密码&#xff1a; grep ‘temporary password’ /var/log/mysqld.log rootlocalhost: b_1sZou9FZrt b_1sZou9FZrt就是 2、修改mysql密码&#xff1a; ALTER USER ‘root’‘localhost’ IDENTIFIED BY ‘new password’; ‘new password’替换成你要设置的密…