- 打家劫舍 III
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
示例 1:
输入: [3,2,3,null,3,null,1]
输出: 7
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.
示例 2:
输入: [3,4,5,1,3,null,1]
1 2 3 4 5
| 3 / \ 4 5 / \ \ 1 3 1
|
输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.
解答
使用后序遍历非递归,分别记录每一个节点的抢劫能抢到的钱,以及不抢它能抢到的钱,总之还是动态规划。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
class Solution { public: int rob(TreeNode* root) { if (!root) { return 0; } unordered_map<TreeNode*, int> data; unordered_map<TreeNode*, int> pre; TreeNode* p = root; stack<TreeNode*> tree; stack<bool> check; while (p || !tree.empty()) { if (p) { tree.push(p); check.push(false); p = p->left; } else { bool need_pop = check.top(); if (need_pop) { TreeNode* check_node = tree.top(); check.pop(); tree.pop(); int check_val = check_node->val;; int pre_val = 0; if (check_node->left) { check_val += pre[check_node->left]; pre_val += data[check_node->left]; } if (check_node->right) { check_val += pre[check_node->right]; pre_val += data[check_node->right]; } data[check_node] = max(check_val, pre_val); pre[check_node] = pre_val; } else { check.pop(); check.push(true); p = tree.top()->right; } } } return data[root]; } };
|
http://www.bilibili.com/video/av23885544/ 这里的后序遍历非递归的说明挺清楚的
后序遍历递归版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
class Solution { public: int rob(TreeNode* root) { if (!root) { return 0; } unordered_map<TreeNode*, int> data; unordered_map<TreeNode*, int> pre; search(root, data, pre); return data[root]; }
void search(TreeNode* check_node, unordered_map<TreeNode*, int>& data, unordered_map<TreeNode*, int>& pre) { int check_val = check_node->val;; int pre_val = 0; if (check_node->left) { search(check_node->left, data, pre); check_val += pre[check_node->left]; pre_val += data[check_node->left]; } if (check_node->right) { search(check_node->right, data, pre); check_val += pre[check_node->right]; pre_val += data[check_node->right]; } data[check_node] = max(check_val, pre_val); pre[check_node] = pre_val; } };
|
其实比上面的要慢,主要是因为unordered_map的使用,其实并不需要用这个map,每一次返回两个数就行
优化
换成返回两个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
class Solution { public: int rob(TreeNode* root) { if (!root) { return 0; } auto ans = search(root); return ans.first; }
pair<int, int> search(TreeNode* check_node) { if (!check_node) { return {0, 0}; } auto left = search(check_node->left); auto right = search(check_node->right); int check_val = check_node->val + left.second + right.second; int pre_val = left.first + right.first; return {max(check_val, pre_val), pre_val}; } };
|