难度中等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<string, int> repeat_tree;
string dfs(TreeNode* root, vector<TreeNode*> &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<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
vector<TreeNode*> nodes;
dfs(root, nodes);
return nodes;
}
};
3.官网解法:用int序号替代string加速相等的判断
class Solution {
public:
vector<TreeNode*> 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<string> 表示出现的重复串 插入根节点
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<tuple<int, int, int>, pair<TreeNode*, int>, decltype(tri_hash)> seen{0, tri_hash};
unordered_set<TreeNode*> repeat;
int idx = 0;
};