House Robber I/II/III

来源:互联网 发布:烟台正浩网络老总 编辑:程序博客网 时间:2024/05/21 22:44






题目分析:

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<int>& nums) {if (nums.size() == 0) return 0;vector<int> 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<int>& nums) {if (nums.size() == 0) return 0;vector<int> 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<int>& nums) {int max = 0;vector<int> av(nums.begin() + 1, nums.end());vector<int> 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<int, int> result = robTree(root);return result.first > result.second ? result.first : result.second;}pair<int, int> robTree(TreeNode* root) {pair<int, int> left_val = make_pair(0, 0);pair<int, int> 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);}


0 0
原创粉丝点击