【LeetCode】动态规划——198.打家劫舍、213.打家劫舍||、337.打家劫舍|||
LeetCode题目链接
https://leetcode.cn/problems/house-robber/
https://leetcode.cn/problems/house-robber-ii/description/
https://leetcode.cn/problems/house-robber-iii/description/
题解
198.打家劫舍
初始化:第一个房屋可抢的最大金额数就是第一个房屋的值,前两个房屋所抢最大金额值就是前两个房屋之中的金额最大值,因此dp[0]和dp[1] = max(…)就初始化好。
递推公式:抢当前房屋时,前一个房屋不能抢,因此要从前两个房屋所抢的值计算当前的值;不抢当前房屋时,所得的最大金额和前一个房屋是相同的,因此直接赋予前一个房屋的值。
特判:由于后续遍历数组时初始值从2开始,因此要对数组长度为1和长度为2时的情况特判,输出相应值。
213.打家劫舍||
环形的拆解方法:首元素和尾元素不能同时取到,因此分为除去尾元素取前n-1个数、除去首元素取后n-1个数这两种情况,由此将环形问题化为线性问题,重复两次计算最大金额数,取两个值的最大值即可。
同时注意特殊情况,在线性情况计算过程中,dp数组初始化时的nums的下标取值为start+1,这要求传入数组下标的距离范围必须大于2,也就是end和start的距离大于1,因此数组需要在长度为2和长度为1时特判(长度为2时start和end相等)。
337.打家劫舍|||
首先明确是后序遍历,【因为要用到先前遍历出来的左结点和右结点值】——来自代码随想录。具体来说,递推公式明确是二维,且用花括号表示,则为vector< int >类型,一维和二维分别表示不偷与偷,当不偷时,根结点所得得最大金额数为左结点和右结点不偷与偷的最大值之和,当偷时,根结点等于左结点和右结点不偷的值加上根结点值之和,需要注意,最终根结点存放的值即为当前不偷与偷所得结果最大值,再取两者之间的最大值即可。
代码
//198.打家劫舍
#include <iostream>
#include <vector>
using namespace std;class Solution {
public:int rob(vector<int>& nums) {if (nums.size() == 1) return nums[0];if (nums.size() == 2) return max(nums[0], nums[1]);vector<int> dp(nums.size(), 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];}
};int main() {Solution s;vector<int> nums = { 1,2,3,1 };printf("%d", s.rob(nums));return 0;
}
//213.打家劫舍||
#include <iostream>
#include <vector>
using namespace std;class Solution {
public:int rob(vector<int>& nums) {//特殊情况if (nums.size() == 1) return nums[0];if (nums.size() == 2) return max(nums[0], nums[1]);int result1 = rob2(nums, 0, nums.size() - 2);int result2 = rob2(nums, 1, nums.size() - 1);return max(result1, result2);}int rob2(vector<int>nums, int start, int end) {//初始化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 - 1], dp[i - 2] + nums[i]);}return dp[end];}
};int main() {Solution s;vector<int> nums = { 1,2,3,1 };printf("%d", s.rob(nums));return 0;
}
//337.打家劫舍|||
#include <iostream>
#include <vector>
using namespace std;struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode() : val(0), left(nullptr), right(nullptr) {}TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}};class Solution {
public:int rob(TreeNode* root) {vector<int> result = rob2(root);return max(result[0], result[1]);}vector<int> rob2(TreeNode* cur) {//特殊情况if (cur == NULL) return vector<int>{0, 0};//后序遍历vector<int> left = rob2(cur->left);vector<int> right = rob2(cur->right);//不偷与偷int val1 = max(left[0], left[1]) + max(right[0], right[1]);int val2 = cur->val + left[0] + right[0];return { val1, val2 };}
};int main() {Solution s;TreeNode* root = new TreeNode(3);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->right = new TreeNode(3);root->right->right = new TreeNode(1);printf("%d", s.rob(root));return 0;
}