难度中等545收藏分享切换为英文接收动态反馈
给定一棵二叉树 root,返回所有重复的子树。
对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。
如果两棵树具有相同的结构和相同的结点值,则它们是重复的。
示例 1:

输入:root = [1,2,3,4,null,2,4,null,null,4] 输出:[[2,4],[4]]
示例 2:

输入:root = [2,1,1] 输出:[[1]]
示例 3:

输入:root = [2,2,2,3,null,3,null] 输出:[[2,3],[3]]
提示:
[1,10^4]范围内。-200 <= Node.val <= 200分析:胡汉三又回来写题了,好久不写题了变得好垃圾了QAQ,疯狂看题解。本题的题意就是输出所有重复子树的根节点,需要注意的是,对于一组重复的子树,输出其中任意一个根即可。
1.想判断两棵树相等,需要把两颗树都遍历一遍,然后看是否相同,后续还要进行去重。。。个屁啊,没事找事,是个思路但是妥妥不对劲
2.针对看一下上述的优化点 ,实际上我们看完整棵树就理应知道所有的子结构了,另外判断结构相似可以比较两个结构的序列化结果;还没完,本题中强调了子树,子树的叶子在原树上也必须是叶子,而且我们很容易发现递归性质--要想判断大一点的结构是否相同,就要先看小一点的结构是否相同,而DFS的返回顺序正好就符合了这一条性质;现在我们来看看怎么去快速查找树中的相似子树结构,实际上上面也提到了,树的结构可以用序列化结果表示,那么我们只需要获取所有的子树,再使用他们的序列化结果进行查询即可。
- /**
- * Definition for a binary tree node.
- * struct TreeNode {
- * int val;
- * TreeNode *left;
- * TreeNode *right;
- * TreeNode() : val(0), left(nullptr), right(nullptr) {}
- * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
- * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
- * };
- */
- class Solution {
- public:
-
- unordered_map
int> repeat_tree; -
- string dfs(TreeNode* root, vector
&nodes) { - if(!root){
- return "";
- }
- string tree_serial = to_string(root -> val) + "(" + dfs(root -> left, nodes) + ")" + "(" + dfs(root -> right, nodes) + ")";
- if(repeat_tree.find(tree_serial) == repeat_tree.end()){
- repeat_tree[tree_serial] = 1;
- } else {
- ++ repeat_tree[tree_serial];
- if(repeat_tree[tree_serial] == 2){
- nodes.emplace(nodes.end(), root);
- }
- }
- return tree_serial;
- }
-
- vector
findDuplicateSubtrees(TreeNode* root) { - vector
nodes; - dfs(root, nodes);
- return nodes;
- }
- };
3.官网解法:用int序号替代string加速相等的判断
- class Solution {
- public:
- vector
findDuplicateSubtrees(TreeNode* root) { - dfs(root);
- return {repeat.begin(), repeat.end()};
- }
-
- int dfs(TreeNode* node) {
- if (!node) {
- return 0;
- }
- auto tri = tuple{node->val, dfs(node->left), dfs(node->right)};
- if (auto it = seen.find(tri); it != seen.end()) {//当前结构出现过
- repeat.insert(it->second.first);//repeat
表示出现的重复串 插入根节点 - return it->second.second;//返回代表当前串的序号 用序号替代string加速匹配
- }
- else {//当前结构没出现过,加入seen集合
- seen[tri] = {node, ++idx};
- return idx;
- }
- }
-
- private:
- static constexpr auto tri_hash = [fn = hash<int>()](const tuple<int, int, int>& o) -> size_t {
- auto&& [x, y, z] = o;
- return (fn(x) << 24) ^ (fn(y) << 8) ^ fn(z);
- };
-
- unordered_map
int, int, int>, pairint>, decltype(tri_hash)> seen{0, tri_hash}; - unordered_set
repeat; - int idx = 0;
- };