一、652. 寻找重复的子树【中】
1、题目:
给定一棵二叉树 root,返回所有重复的子树。
对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。
如果两棵树具有相同的结构和相同的结点值,则它们是重复的。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/special-positions-in-a-binary-matrix
我的思路是深度优先,去用数组记录每个节点的左右子树。如下图,值为3的结点左子树为[4,2],右子树为[4]。这样很直观能看出哪些子树是相等的,但在程序上引来两个问题:
- 数组个数会有多个,如何知道这些数组哪些是相等的?
- 知道了相等的两个数组后,怎么知道这个数组是哪个节点的子树?
2、思路一:深度优先+字符串哈希表
依然是深度优先,不同的是数组被替换成了字符串去描述一颗子树,再使用字符串哈希表,记录每种子树出现的次数,若在遍历过程中,子树字符串出现次数等于两次时,即记录该节点。
等于是因为,若多个子树是相同的,只需要返回一个子树的根即可。
代码(错误):
class Solution {
public:
vector<TreeNode*> result; //结果节点
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
unordered_map<string,int> map; //记录子树出现次数的字符串哈希表
dfs(root,map);
return result;
}
//dfs
string dfs(TreeNode* node, unordered_map<string,int>& map){
if(!node) return "";
string left = dfs(node->left, map);
string right = dfs(node->right, map);
string current = left+to_string(node->val)+right;
map[current] ++; // 记录该子树
if(map[current]==2) result.push_back(node); // 出现次数为2次
return current;
}
};
思路没问题,但代码错了,该例子可视化后:
发现,子树也需要区分左右。那么在每次将左子树、右子树、节点连接成子树字符串返回上层时,左子树前加“(”,右子树前加“)”即可。
官解分析的时间复杂度:
代码:
//s:O(n) t:O(n)
class Solution {
public:
vector<TreeNode*> result; //结果节点
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
unordered_map<string,int> map; //记录子树出现次数的字符串哈希表
dfs(root,map);
return result;
}
//dfs
string dfs(TreeNode* node, unordered_map<string,int>& map){
if(!node) return "";
string left = "("+dfs(node->left, map);
string right = ")"+dfs(node->right, map);
string current = left+to_string(node->val)+right;
map[current] ++; // 记录该子树
if(map[current]==2) result.push_back(node); // 出现次数为2次
return current;
}
};
3、思路二 :使用三元组进行唯一表示(待定)
例子:
代码:
//s:O() t:O()