力扣337. 打家劫舍 III

Posted weixin_43739821

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了力扣337. 打家劫舍 III相关的知识,希望对你有一定的参考价值。

原题:
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。

除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。

给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。

意思是: 带权二叉树在不能同时选择父子结点的情况下能得到最大权值是多少

错误思路: 想着用层序遍历把每层结点权值和先算出来,然后用二维dp,第一层遍历了那么第二层就不能遍历了
错误代码:

vector<int> levelOrder(TreeNode* root) 
	vector <int> ret;
	if (!root) 
		return ret;
	
	queue <TreeNode*> q;
	q.push(root);
	while (!q.empty()) 
		int currentLevelSize = q.size();
		int x = 0;
		for (int i = 1; i <= currentLevelSize; ++i) 
			auto node = q.front(); q.pop();
			x+=node->val;
			if (node->left) q.push(node->left);
			if (node->right) q.push(node->right);
		
		ret.push_back(x);
	
	return ret;

int rob(TreeNode* root) 
	if (!root) return 0;
	vector<int> nums= levelOrder(root);
	int n = nums.size();
	if (n == 1) return nums[0];
	vector<vector<int>>dp(n, vector<int>(2, 0));//[i][0]表示第i个不偷,[i][1]表示第i个偷
	dp[0][0] = 0;
	dp[0][1] = nums[0];
	dp[1][0] = dp[0][1];
	dp[1][1] = nums[1];
	if (n == 2) return max(dp[1][0], dp[1][1]);
	for (int i = 2; i < n; i++) 
		dp[i][0] = max(dp[i - 1][1], dp[i - 1][0]);
		dp[i][1] = nums[i] + dp[i - 1][0];
	
	return max(dp[n - 1][0], dp[n - 1][1]);

然后一想想好像不对劲,反例很好举:

比如这种情况,上面的运行结果是6,正确答案应该是7

正确思路: 递归后序遍历+自下而上动态规划+哈希表存储
用哈希表f存储选这个结点则该结点包括其子树能偷到的最大金额,g存储不偷这个结点则其俩子树能偷到的最大金额
则f[root] = root->val + g[root->left] + g[root->right];
g[root] = max(g[root->right], f[root->right]) + max(g[root->left], f[root->left]);
自下而上 最后返回max(f[root], g[root])即可
代码:

unordered_map<TreeNode*,int> f, g;//

void dfs(TreeNode* root) //用递归形式后序遍历,自下而上动态规划
	if (!root) return;//空结点
	dfs(root->left);
	dfs(root->right);
	f[root] = root->val + g[root->left] + g[root->right];//选了这个结点,则其俩个子结点都不能选了,所以都是g,若其子节点不存在,map返回的是0
	g[root] = max(g[root->right], f[root->right]) + max(g[root->left], f[root->left]);//不选这个结点,则左右结点均可选或不选,左右各自取最大就行

int rob(TreeNode* root) 
	dfs(root);
	return max(f[root], g[root]);

时间空间均为O(n),其中空间还可以优化,因为父结点只会用到子结点的f和g,可以让dfs返回一个struct包含子结点的f和g,但是因为递归调用栈的原因,空间还是O(n)

以上是关于力扣337. 打家劫舍 III的主要内容,如果未能解决你的问题,请参考以下文章

力扣337. 打家劫舍 III

LeetCode 0337. 打家劫舍 III

题目地址(337. 打家劫舍 III)

337.打家劫舍 III

337.打家劫舍 III

Leetcode 337. 打家劫舍 III