好久没有一把过了
本人语文水平不咋地,代码也写的不咋样
欢迎大家的评判与指正
总体思路:
自底向上的找出每个节点被打劫和不被打劫时,两种情况下的最大值
然后每个节点就可以根据自身的情况来找出,以当前节点为根节点时的最优解
当 当前节点被打劫时,两个子节点一定不会被打劫,则用当前节点的值+两个子节点都没有被打劫时的最大值
当 当前节点被打劫时,则两个子节点可能被打劫,也有可能不被打劫,所以就用0+左节点在两种情况下的最大值+右节点在两种情况下的最大值
static const auto io_sync_off = []() { // turn off sync std::ios::sync_with_stdio(false); // untie in/out streams std::cin.tie(nullptr); return nullptr; }(); /** * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * }; */ class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param root TreeNode类 * @return int整型 */ int rob(TreeNode* root) { // write code here int answer = 0; if (!root) { return 0; } else if (nullptr == root->left && nullptr == root->right) { return root->val; } // levelTree中的每一个元素都是一个map // map的键为树中元素的位置(根节点位置为1,除根节点外任意左节点为其父节点的位置*2,任意右节点的位置为其父节点的位置*2+1) // map的值为两个int // 第一个int为,以当前节点为根节点的树中,该节点不被"打劫"时的最大值 // 第二个int为,以当前节点为根节点的树中,该节点被"打劫"时的最大值 vector<map<int, pair<int, int>>> levelTree; // 下面两个deque是为了实现层次遍历 deque<pair<int, TreeNode*>> q1; deque<pair<int, TreeNode*>> q2; q1.push_back({1, root}); // level存放层次遍历中,同一行中的所有元素 map<int, pair<int, int>> level; // 根节点的位置设置为1 level.insert({1, {root->val, 0}}); levelTree.push_back(level); // 将node节点声明在while外,是为了减少频繁声明局部变量而带来的消耗 pair<int, TreeNode*> node = {0, nullptr}; while (!q1.empty()) { level.clear(); while (!q1.empty()) { node = q1.front(); q1.pop_front(); if (node.second->left) { // 层次遍历时,得额外记一下节点的位置,要不然在遍历的时候,无法设定子节点的位置 q2.push_back({node.first * 2, node.second->left}); level.insert({node.first * 2, {node.second->left->val, 0}}); } if (node.second->right) { q2.push_back({node.first * 2 + 1, node.second->right}); level.insert({node.first * 2 + 1, {node.second->right->val, 0}}); } } if (!level.empty()) { levelTree.push_back(level); } while (!q2.empty()) { node = q2.front(); q2.pop_front(); q1.push_back(node); } } // 不考虑只有一层的情况,只有一层的情况单独处理 // rebegin时为了自底向上的遍历树节点 // rbegin()+1是不想在最底层浪费时间 // 因为最底层都是叶子节点,不可能有子节点 // 其被打劫的情况下,得到的最大值就是当前节点 // 其不被打劫时,得到的最大值就是0 for (auto it = levelTree.rbegin() + 1; it != levelTree.rend(); it++) { // 由于使用rbegin,所以当前层的底下一层应该是it-1 auto& nextLevel = *(it - 1); auto& curLevel = *it; for (auto i = curLevel.begin(); i != curLevel.end(); i++) { // 获取当前节点的左右节点,分别在两种情况(被打劫或不被打劫)下的最大值 pair<int, int> left = {0, 0}; pair<int, int> right = {0, 0}; // 这里可以根据当前节点的位置,直接算出其两个子节点的位置,然后去下一层去找 auto l = nextLevel.find((*i).first * 2); auto r = nextLevel.find((*i).first * 2 + 1); if (l != nextLevel.end()) { left = (*l).second; } if (r != nextLevel.end()) { right = (*r).second; } // 当前节点被打劫时,它的两个子节点必定不会被打劫 (*i).second.first += left.second + right.second; // 当前节点不被打劫时,则分别取其两个节点在两种情况中更大的值 (*i).second.second += max(left.first, left.second) + max(right.first, right.second); } } answer = max((*(levelTree[0].begin())).second.first, (*(levelTree[0].begin())).second.second); return answer; } };