网站品牌词优化怎么做,昆明快速做网站,wordpress 20theme,云龙微网站开发目录
198.打家劫舍#xff08;线性#xff09;
动态规划法
213.打家劫舍II#xff08;环形#xff09;
动态规划法
337.打家劫舍III#xff08;二叉树#xff09;
动态规划法 198.打家劫舍#xff08;线性#xff09; 题目链接#xff1a;198. 打家劫舍 - 力扣线性
动态规划法
213.打家劫舍II环形
动态规划法
337.打家劫舍III二叉树
动态规划法 198.打家劫舍线性 题目链接198. 打家劫舍 - 力扣LeetCode 文章讲解代码随想录
动态规划法 解题思路 当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。所以这里就更感觉到当前状态和前面状态会有一种依赖关系那么这种依赖关系都是动态规划的递推公式。 解题步骤 确定dp数组dp table以及下标的含义dp[i]考虑下标i包括i以内的房屋最多可以偷窃的金额为dp[i]。 确定递推公式决定dp[i]的因素就是第i房间偷还是不偷。 如果偷第i房间那么dp[i] dp[i - 2] nums[i] 即第i-1房一定是不考虑的找出 下标i-2包括i-2以内的房屋最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。 如果不偷第i房间那么dp[i] dp[i - 1]即考虑i-1房注意这里是考虑并不是一定要偷i-1房这是很多同学容易混淆的点 然后dp[i]取最大值即dp[i] max(dp[i - 2] nums[i], dp[i - 1]); dp数组如何初始化从递推公式dp[i] max(dp[i - 2] nums[i], dp[i - 1]);可以看出递推公式的基础就是dp[0] 和 dp[1]从dp[i]的定义上来讲dp[0] 一定是 nums[0]dp[1]就是nums[0]和nums[1]的最大值即dp[1] max(nums[0], nums[1]); 确定遍历顺序dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的那么一定是从前到后遍历。 举例推导dp数组 代码注意 初值设置 代码一动态规划
// 时间复杂度: O(n)
// 空间复杂度: O(n)
class Solution {
public:int rob(vectorint nums) {if (nums.size() 0) return 0;if (nums.size() 1) return nums[0];vectorint dp(nums.size());dp[0] nums[0];dp[1] max(nums[0], nums[1]);for (int i 2; i nums.size(); i) {dp[i] max(dp[i - 2] nums[i], dp[i - 1]);}return dp[nums.size() - 1];}
};
213.打家劫舍II环形 题目链接213. 打家劫舍 II - 力扣LeetCode 文章讲解代码随想录
动态规划法 解题思路 对于一个数组成环的话主要有如下三种情况注意这里用的是考虑例如情况三虽然是考虑包含尾元素但不一定要选尾部元素 对于情况三取nums[1] 和 nums[3]就是最大的。而情况二和情况三都包含了情况一了所以只考虑情况二和情况三就可以了。 情况一考虑不包含首尾元素 情况二考虑包含首元素不包含尾元素 情况三考虑包含尾元素不包含首元素 解题步骤 同打家劫舍1只是抽离分情况 代码一动态规划
// 注意注释中的情况二情况三以及把198.打家劫舍的代码抽离出来了
class Solution {
public:int rob(vectorint nums) {if (nums.size() 0) return 0;if (nums.size() 1) return nums[0];int result1 robRange(nums, 0, nums.size() - 2); // 情况二int result2 robRange(nums, 1, nums.size() - 1); // 情况三return max(result1, result2);}// 198.打家劫舍的逻辑int robRange(vectorint nums, int start, int end) {if (end start) return nums[start];vectorint dp(nums.size());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];}
};
337.打家劫舍III二叉树 题目链接337. 打家劫舍 III - 力扣LeetCode 文章讲解代码随想录
动态规划法 解题思路 对于树的话首先就要想到遍历方式前中后序深度优先搜索还是层序遍历广度优先搜索。本题一定是要后序遍历因为通过递归函数的返回值来做下一步计算。与198.打家劫舍213.打家劫舍II一样关键是要讨论当前节点抢还是不抢。如果抢了当前节点两个孩子就不能动如果没抢当前节点就可以考虑抢左右孩子注意这里说的是“考虑” 动态规划其实就是使用状态转移容器来记录状态的变化这里可以使用一个长度为2的数组记录当前节点偷与不偷所得到的的最大金钱。以二叉树递归三部曲为框架其中融合动规五部曲。 解题步骤 确定递归函数的参数和返回值要求一个节点偷与不偷的两个状态所得到的金钱那么返回值就是一个长度为2的数组。所以dp数组dp table以及下标的含义下标为0记录不偷该节点所得到的的最大金钱下标为1记录偷该节点所得到的的最大金钱。所以本题dp数组就是一个长度为2的数组 确定终止条件在遍历的过程中如果遇到空节点的话很明显无论偷还是不偷都是0所以就返回。这也相当于dp数组的初始化。 确定遍历顺序首先明确的是使用后序遍历。 因为要通过递归函数的返回值来做下一步计算。通过递归左节点得到左节点偷与不偷的金钱。通过递归右节点得到右节点偷与不偷的金钱。 确定单层递归的逻辑如果是偷当前节点那么左右孩子就不能偷val1 cur-val left[0] right[0]; 如果对下标含义不理解就再回顾一下dp数组的含义如果不偷当前节点那么左右孩子就可以偷至于到底偷不偷一定是选一个最大的所以val2 max(left[0], left[1]) max(right[0], right[1]);最后当前节点的状态就是{val2, val1}; 即{不偷当前节点得到的最大金钱偷当前节点得到的最大金钱} 例推导dp数组以示例1为例dp数组状态如下注意用后序遍历的方式推导 代码一x动态规划
// 时间复杂度O(n)每个节点只遍历了一次
// 空间复杂度O(log n)算上递推系统栈的空间
class Solution {
public:int rob(TreeNode* root) {vectorint result robTree(root);return max(result[0], result[1]);}// 长度为2的数组0不偷1偷vectorint robTree(TreeNode* cur) {if (cur NULL) return vectorint{0, 0};vectorint left robTree(cur-left);vectorint right robTree(cur-right);// 偷cur那么就不能偷左右节点。int val1 cur-val left[0] right[0];// 不偷cur那么可以偷也可以不偷左右节点则取较大的情况int val2 max(left[0], left[1]) max(right[0], right[1]);return {val2, val1};}
};