动态规划
一、打家劫舍
确定递推公式,当前节点分为偷与不偷两种状态,类似于背包问题
class Solution {
public:
int rob(vector<int>& nums) {
//不能取相邻的两个数值,同时要拿到最高金额
//dp[j]表示遍历到j时,能够取到的最大价值
//递推公式:与前两个房屋有关,偷还是不偷,两种状态
vector<int>dp(nums.size(), 0);
if (nums.size() == 0) return 0;
if (nums.size() == 1) return nums[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];
}
};
二、打家劫舍II
同样的思路但多了条限制条件,分为两种情况讨论,不包含尾元素和不包含首元素
class Solution {
public:
int tra(vector<int>& nums, int start, int end) {
if (start == end) return nums[start];
vector<int>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-1], dp[i-2] + nums[i]);
}
return dp[end];
}
int rob(vector<int>& nums) {
//所有的房屋连成环,第一种情况不带尾元素,第二种情况不带首元素
if (nums.size() == 0) return 0;
if (nums.size() == 1) return nums[0];
int a1 = tra(nums, 0, nums.size()-2);
int a2 = tra(nums, 1, nums.size()-1);
if (a1 > a2) return a1;
return a2;
}
};
三、打家劫舍III
二叉树的系统栈可以保存每一层的参数。确定dp数组,dp[0]表示偷当前节点,dp[1]表示不偷当前节点。从低向上遍历,需要通过递归函数的返回值进行下一步计算。递归三部曲和动规五部曲的结合
/**
* Definition for a binary tree node.
* 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:
vector<int> traversal(TreeNode* root) {
if (root == nullptr) return {0, 0};
vector<int> left = traversal(root->left);
vector<int> right = traversal(root->right);
//偷当前节点
int val1 = root->val + left[0] + right[0];
//不偷当前节点
int val2 = max (left[0], left[1]) + max (right[0], right[1]);
return {val2, val1};
}
int rob(TreeNode* root) {
//相邻节点不能同时取,也是存在两种状态,偷或者不偷
vector<int>res = traversal(root);
return max(res[0], res[1]);
}
};
总结
第三题还是有些绕,不太好理解
学习时间90min。
学习资料:《代码随想录》。