题目分析:
1. House Robber的三道题基本上都大同小异,因此是一次连续做完的。
2. 题目主要的类型是类似动态规划中的背包问题,带有的限制是不能够连续取数,但没有重量的限制。三道题的区别是House Robber I是在普通的线性序列上取数,House Robber II是在环上取数,House Robber III是在二叉树上取数。三道问题可以用类似的思路解决。
3. 首先考虑House Robber I,在线性序列上取数,不能够连续取。因此很自然想到从左到右依次取,对每个状态分为两个子状态,一个是取当前的数,一个是不取当前的数。而取当前数的状态只能够从不取上一个数的状态转移而来,同时价值比不取上一个数的状态增加当前数的价值。不取当前数的状态能够从取和不取上一个数的状态转移而来,价值等于转移前的值。又因为要取最大的价值,所以不取当前数的状态的价值等于 MAX{取上一个数的状态的价值,不取上一个数的状态的价值}
根据这个分析列状态转移方程有
f1[k] = f0[k-1] + v[k]// 取当前值
f0[k] = max(f0[k-1], f1[k-1]) // 不取当前值
根据方程写代码可以解决House Robber I。
4. 然后考虑House Robber II,在环上取数,环上取数的问题在于连接处的取值,其他部分都是和线性序列上的取数一样。而经过观察可以显然得到v[0] 和 v[n-1] 是不可能同时选取的,也即序列[0..n-2] 和序列[1..n-1]的取法是完全没有关系的,因此问题就转化为了求两个线性序列的House Robber I问题,然后再从中选取最大值即可。根据这个思路写代码直接用上House Robber I的函数可以解决House Robber II。
5. House Robber III是在二叉树上取数,但其实问题并没有比House Robber I复杂太多,只需要从叶节点开始向上推,同样求出每个 节点k对应的f0[k]和f1[k]即可。为了从叶节点开始向上推采用后序遍历的方式。对应的方程如下
f1[k] = max(f0[left], f0[right]) + v[k]// 取当前值
f0[k] = max(f0[left], f1[left], f0[right], f1[right]) // 不取当前值
int rob(vector& nums) {
if (nums.size() == 0) return 0;
vector f1(nums.size(), 0), f2(nums.size(), 0);
f1[0] = nums[0];
f2[0] = 0;
for (int i = 1; i < nums.size(); i++) {
f1[i] = f2[i - 1] + nums[i];
f2[i] = f1[i - 1] > f2[i - 1] ? f1[i - 1] : f2[i - 1];
}
return f1[nums.size() - 1] > f2[nums.size() - 1] ? f1[nums.size() - 1] : f2[nums.size() - 1];
}
int robOnce(vector& nums) {
if (nums.size() == 0) return 0;
vector f1(nums.size(), 0), f2(nums.size(), 0);
f1[0] = nums[0];
f2[0] = 0;
for (int i = 1; i < nums.size(); i++) {
f1[i] = f2[i - 1] + nums[i];
f2[i] = f1[i - 1] > f2[i - 1] ? f1[i - 1] : f2[i - 1];
}
return f1[nums.size() - 1] > f2[nums.size() - 1] ? f1[nums.size() - 1] : f2[nums.size() - 1];
}
int rob(vector& nums) {
int max = 0;
vector av(nums.begin() + 1, nums.end());
vector bv(nums.begin(), nums.end() - 1);
int a = robOnce(av);
int b = robOnce(bv);
return a > b ? a : b;
}
int max(int a, int b, int c, int d) {
if (a < b) a = b;
if (c < d) c = d;
if (a < c) a = c;
return a;
}
int rob(TreeNode* root) {
if (root == NULL) return 0;
pair result = robTree(root);
return result.first > result.second ? result.first : result.second;
}
pair robTree(TreeNode* root) {
pair left_val = make_pair(0, 0);
pair right_val = make_pair(0, 0);
if (root->left == root->right && root->right == NULL)
return make_pair(root->val, 0);
if (root->left != NULL) left_val = robTree(root->left);
if (root->right != NULL) right_val = robTree(root->right);
int chosen = left_val.second + right_val.second + root->val;
int not_chosen = max(left_val.second + right_val.second, left_val.first + right_val.second, left_val.second + right_val.first, +left_val.first + right_val.first);
return make_pair(chosen, not_chosen);
}