您的位置:首页 > 职场人生

Uber面试题2 | House Robber III

2016-05-04 16:48 477 查看
题目描述 

小偷找到了一个新的偷盗地点,这里地区的房子组成了一棵二叉树,地区的入口是二叉树的根所在的房子。如果小偷同时偷窃了两个直接相邻的房子,就会触发警报器。求在不触发警报器的情况下小偷可以抢到的最多的money
4000


Example:

3
/ \
2   3
\   \
3   1


小偷可以抢到的最多的money是3+3+1=7(偷窃带下划线的房子)

算法分析

本题是House Robber的follow up。House Robber-i中房子排列成一个序列,House Robber-ii中房子排列成一个环,均可以用动态规划解决。

这里简单分析一下房子排成一个序列的情况,直觉上我们应该尽量偷价值高的房子,但因为有限制条件不能偷相邻的房子,直接贪心不可行。考虑动态规划,如果我们已知前k个房子可能偷到的最高价值,当k等于n时我们也就得到了全局最优解;同时,前k个房子能偷到的最高价值可以通过对第k个房子做决策(偷或者不偷),从比k小的局部最优解中得到。

对于本问题,由于是树上的问题, 我们有一种dp类型是,在树上一边搜索,一边利用dp数组保存状态,所以我们叫他树形dp,这是一类型大家没怎么见过的新题型。假设我们已知了根节点的左右子树的局部最优解,通过对根节点所在的房子进行决策:偷或者不偷,我们就可以得到全局最优解。具体算法过程如下: 递归先求得左右子树的局部最优解,分别表示该子树根节点的房子偷和不偷所能得到的最高价值,再得到了左右子树的返回值后,对于本层更新,我们需要考虑,1.左右儿子不偷的时候我们当前可以偷本层,2.左右儿子都偷的时候我们当前本层则不能偷。

具体动态规划四要素为:

Definition:

dp[i][0]表示以i为根的子树不偷根节点能获得的最高价值,dp[i][1]表示以i为根的子树偷根节点能获得的最高价值

Function:

dp[i][0] = max(dp[left[i]][0], dp[left[i]][1]) + max(dp[right[i]][0], dp[right[i]][1]);

dp[i][1] = dp[left[i]][0] + dp[right[i]][0];

Intialize: 

空节点的dp值均为0

Answer: 

dp[root][0]和dp[root][1]中的较大值

最后返回根节点的两个dp值中较大的那个即可。

/**
* Definition of TreeNode:
* class TreeNode {
* public:
*     int val;
*     TreeNode *left, *right;
*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* }
*/
class Solution {
private:
void visit(TreeNode* root, int &rob, int ¬_rob) {
rob = not_rob = 0;
if (root == NULL)
return;

int left_rob, left_not_rob, right_rob, right_not_rob;
visit(root->left, left_rob, left_not_rob);
visit(root->right, right_rob, right_not_rob);

rob = left_not_rob + right_not_rob + root->val;
not_rob = max(left_rob, left_not_rob) + max(right_rob, right_not_rob);
}
public:
/**
* @param root: The root of binary tree.
* @return: The maximum amount of money you can rob tonight
*/
int houseRobber3(TreeNode* root) {
// write your code here
int rob, not_rob;
visit(root, rob, not_rob);
return max(rob, not_rob);
}
};


面试官角度分析

本题可以用搜索解决,但面试官考察的是对树和动态规划的理解。给出基于动态规划思想的O(n)可达到hire的程度,n为总房子数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: