198. 打家劫舍 - 力扣(LeetCode)
动归五部曲:
1.确定dp数组及下标含义: dp[i]: 考虑下标i(包括i)以内的房屋,最多可以偷窃的金额;
2.确定递推公式: dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
3.dp数组如何初始化:dp[0] = nums[0]; dp[1] = max(nums[0], nums[1]);
4.确定遍历顺序:从前到后遍历;
5.举例递推dp数组;
代码:
class Solution {
public:
int rob(vector& nums) {
if (nums.size() == 0) return 0;
if (nums.size() == 1) return nums[0];
vector 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];
}
};
时间复杂度: O(n) 空间复杂度:O(n)
213. 打家劫舍 II - 力扣(LeetCode)
思路:
相较于 LeeCode 198.打家劫舍 ,本题条件限制首尾房屋相连,可以分成两种情况讨论——考虑包含首元素,不包含尾元素 / 考虑包含尾元素,不包含首元素。(考虑不代表一定选中)
代码:
class Solution {
public:
int rob(vector& 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);
}
int robRange(vector& nums, int start, int end) {
if (end == start) return nums[start];
vector 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];
}
};
时间复杂度: O(n) 空间复杂度:O(n)
337. 打家劫舍 III - 力扣(LeetCode)
动归五部曲:
1.确定dp数组及下标含义: dp数组是长度为2的数组,在递归过程中,系统栈会保存每一层递归的参数,因此dp数组可以标记树中每个节点的状态;dp[i]: 下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱;
2.确定递推公式: dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
3.dp数组如何初始化:if (cur == NULL) return vector
4.确定遍历顺序:后序遍历;
5.举例递推dp数组;
代码:
class Solution {
public:
int rob(TreeNode* root) {
vector result = robTree(root);
return max(result[0], result[1]);
}
vector robTree(TreeNode* cur) {
if (cur == NULL) return vector{0,0};
vector left = robTree(cur->left);
vector right = robTree(cur->right);
int val1 = cur->val + left[0] + right[0];
int val2 = max(left[0], left[1]) + max(right[0], right[1]);
return {val2,val1};
}
};
时间复杂度: O(n) 空间复杂度:O(log n)