House Robber I/II/III

House Robber I/II/III_第1张图片


House Robber I/II/III_第2张图片

House Robber I/II/III_第3张图片


题目分析:

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);
	}


你可能感兴趣的:(LeetCode)