题目描述:
给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。
两棵树重复是指它们具有相同的结构以及相同的结点值。
示例 1:
1
/ \
2 3
/ / \
4 2 4
/
4
下面是两个重复的子树:
2
/
4
和
4
因此,你需要以列表的形式返回上述重复子树的根结点。
来源:力扣(LeetCode)
链接:寻找重复的子树
思路:
刚开始我的思路算是属于暴力破解,就是对于每一个节点,去搜索整棵数的其他节点(不搜索所要进行对比的节点以下的其他子节点)与其比较,从而来获取结果,但后面发现实现起来很麻烦,而且效率也非常低下,所以就在领扣题解里面参考以下大佬们的解法,看到一种序列化二叉树的方法,可以利用将节点及以下部分序列化后的结果作为该节点的特征值,因为每个节点序列化后的结果是唯一地,除非他们是重复的子树,这样一来就可以通过比较序列化后的结果来判断是否是重复的子树,但是如果只是将序列化后的结果作为该节点的特征值保存在该节点上,寻找的时候效率会非常低,所以这里需要将特征值用一个容器保存起来,不仅要保存该特征值,还需要保存该特征值出现了几次,如果所判断的节点的特征值在容器中出现过一次,说明重复了,进行重复子树的保存,但是如果出现超过一次则说明已经找到过一个,不用重复保存,这里的容器可以使用map,具体的算法:寻找重复子树题解。
序列化: 比如示例1中的树,通过深度优先遍历的序列化后的结果为:124###324###4##(这个属于先序遍历,也可以使用中序和后序),序列化结果中的‘#’表示节点为空。
主要代码:
struct TreeNode {//二叉数节点的结构体
int val;//节点值
TreeNode* left;//左孩子
TreeNode* right;//右孩子
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
//二叉树重复子树
map<string, int> Store;//存放以每个节点为根节点的子树序列化后的结果,string存放序列化结果,int存放出现的次数
vector<TreeNode*> ans;//存放重复子树的根节点
string FindString(TreeNode* root) {
if (!root)//如果该节点为空,返回‘#’
return "#";
string temp;//存放root为根节点子树序列化后的结果
temp = (char)(root->val + '0') + FindString(root->left) + FindString(root->right);//先序遍历所得的序列化结果
if (Store.find(temp) != Store.end())//如果存放序列化结果的容器中存在刚得到的结果
{
if(Store[temp] == 1)//如果只出现一次,才将该节点存放进存放重复子树的根节点的容器中
ans.push_back(root);
Store[temp] +=1 ;//出现次数加1
}
else {
Store[temp] = 1;//如果没出现,则保存该结果,并将次数置为1
}
return temp;//返回序列化结果
}
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
FindString(root);
return ans;
}