【力扣一刷】代码随想录day48(动态规划part9 - 打家劫舍专题:198.打家劫舍、213.打家劫舍II 、337.打家劫舍III)
当数组中只有两个元素时,不进入for循环,此时y就是答案,所以最后的返回值不能是z,只能是y。
class solution {
public int rob(int[] nums) {
// dp[i]:从0到i间房子中一夜之内能偷窃到的最高金额
// 偷:dp[i] = dp[i-2] + nums[i]
// 不偷:dp[i] = dp[i-1] (最高金额还是和从0到i-1间房子中一夜之内能偷窃到的最高金额一致)
if (nums.length < 2) return nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0]; // 只有一间房,那肯定偷
dp[1] = math.max(nums[0], nums[1]); // 有两间房(必定相邻),只能选其中最高金额的偷
for (int i = 2; i < dp.length; i++){
dp[i] = math.max(dp[i-1], dp[i-2] + nums[i]);
}
return dp[nums.length-1];
}
}
- 时间复杂度:o(n),n是nums数组的长度,for循环遍历了一次
- 空间复杂度:o(n),dp数组的长度等于nums数组的长度
【优化】 空间复杂度o(n) -> o(1)
class solution {
public int rob(int[] nums) {
// z:从0到i间房子中一夜之内能偷窃到的最高金额
// 偷:z = x + nums[i]
// 不偷:z = y (最高金额还是和从0到i-1间房子中一夜之内能偷窃到的最高金额一致)
if (nums.length < 2) return nums[0];
int x = nums[0];
int y = math.max(nums[0], nums[1]);
int z = 0;
for (int i = 2; i < nums.length; i++){
z = math.max(y, x + nums[i]);
x = y;
y = z;
}
return y;
}
}
- 时间复杂度:o(n),n是nums数组的长度,for循环遍历了一次
- 空间复杂度:o(1),无论输入的nums数组多长,都只用三个变量就足够
class solution {
public int rob(int[] nums) {
if (nums.length < 2) return nums[0];
int dp1 = robsimple(nums, 0, nums.length-2); // 不偷尾元素
int dp2 = robsimple(nums, 1, nums.length-1); // 不偷头元素
return math.max(dp1, dp2);
}
// 根据索引求nums某区间内的最高金额
public int robsimple(int[] nums, int start, int end){
if (end == start) return nums[start];
int x = nums[start]; // 只有一间房,那肯定偷
int y = math.max(nums[start], nums[start+1]); // 有两间房(必定相邻),只能选其中最高金额的偷
for (int i = start+2; i < end+1; i++){
int z = math.max(y, x + nums[i]);
x = y;
y = z;
}
return y;
}
}
- 时间复杂度:o(n),n是nums数组的长度
- 空间复杂度:o(1),无论输入的nums数组多长,都只用三个变量就足够

class solution {
int sons = 0;
public int rob(treenode root) {
return robdfs(root);
}
// 递归 - 后序遍历(左右中)
public int robdfs(treenode root){
// 递归的终止条件
if (root == null) {
sons = 0; // 空节点的所有孩子最高金额的和为0
return 0; // 空节点的最高金额也为0
}
// 规则:
// -不偷:偷所有儿子的 = 最高金额选择1
// -偷:偷自己的 + 所有孙子的 = 最高金额选择2
int grandsons = 0;
int leftson = robdfs(root.left); // 获取左儿子的最高金额
grandsons += sons; // 左儿子的儿子是孙子的一部分
int rightson = robdfs(root.right); // 获取右儿子的最高金额
grandsons += sons; // 右儿子的而是是孙子的另一部分
sons = leftson + rightson; // 左儿子的最高金额 + 右儿子的最高金额 = 所有儿子的最高金额的和
return math.max(sons, grandsons + root.val); // 选偷和不偷的最高金额
}
}
- 时间复杂度:o(n),n是所有节点的个数,递归遍历所有节点一次
- 空间复杂度:o(log n),递归栈所占的空间=二叉树的深度
相关文章:
-
【C语言】深入解析插入排序
插入排序(Insertion Sort)是一种基于比较的排序算法。它的基本思想是将元素逐个插入到已排序的部分中,使整个序列保持有序。插入排序在处理小数据集或几乎...
[阅读全文]
-
这篇文章详细介绍了C++标准库中的无序关联容器unordered_set和unordered_map,它们基于哈希表实现,提供了高效的增删查改操作。这些容器允许存储唯一元素(对于u…
-
上一篇章学习了位图的使用,但它只适用于整数,对于要查询字符串是否在不在,位图并不能解决。所以针对这一问题,布隆过滤器可以派上用场,至于布隆过滤器是什么,其实并没有什么神奇的,就是在…
-
给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。遍历,时间复杂度O(N)。排序(O(NlogN)),利用二分查找:logN。位图解…
-
-
算法系列篇-哈希表:两数之和、判定是否为字符重排、存在重复元素、存在重复元素II、字母异位词分组…
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论