深度优先(C++)
解题思路:将每一棵子树序列化,即对于一棵子树,转化为:
s t r i n g ( r o o t ) + s t r i n g ( r o o t . l e f t ) + s t r i n g ( r o o t . r i g h t ) string(root)+string(root.left)+string(root.right) string(root)+string(root.left)+string(root.right)
对于这个序列需要使用一个散列表来储存其出现的次数,如果次数为1,即之前遇到过一次,就将该根节点放入结果列表中;否则不放入。
必备C++STL知识:map和unorderedmap的区别和使用
class Solution {
public:
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
vector<TreeNode*> res; // 存放结果根节点
unordered_map<string, int> mp; // 存放序列化子树的出现次数
helper(root, mp, res);
return res;
}
string helper(TreeNode* root, unordered_map<string, int>&mp, vector<TreeNode*>&res){
if(!root) return "#";
string str;
// 序列化子树
str = to_string(root->val) + ' ' + helper(root->left, mp, res) + ' '+ helper(root->right, mp, res);
// 如果str不存在mp中,mp[str]==0
if(mp[str] == 1) res.push_back(root);
mp[str]++;
return str;
}
};
深度优先(python)
思路和递归实现的C++版本一致:
python必备知识:collections.defaultdict的使用1
collections.defaultdict的使用2
python的collections库的使用1
python的collections库的使用2
class Solution:
def findDuplicateSubtrees(self, root: TreeNode) -> List[TreeNode]:
cnt = collections.Counter()
res = []
def helper(root):
if not root:
return '#'
string = "{:},{:},{:}".format(root.val, helper(root.left), helper(root.right))
if cnt[string] == 1:
res.append(root)
cnt[string]+=1
return string
helper(root)
return res
时间复杂度: O ( N 2 ) O(N^2) O(N2),其中 N N N 是二叉树上节点的数量。遍历所有节点,在每个节点处序列化需要时间 O ( N ) O(N) O(N)。
空间复杂度: O ( N 2 ) O(N^2) O(N2), c o u n t count count 的大小。
唯一标识符
class Solution(object):
def findDuplicateSubtrees(self, root):
trees = collections.defaultdict()
trees.default_factory = trees.__len__
count = collections.Counter()
ans = []
def lookup(node):
if node:
uid = trees[node.val, lookup(node.left), lookup(node.right)]
count[uid] += 1
if count[uid] == 2:
ans.append(node)
return uid
lookup(root)
return ans
时间复杂度: O ( N ) O(N) O(N),其中 N N N二叉树上节点的数量,每个节点都需要访问一次。
空间复杂度: O ( N ) O(N) O(N),每棵子树的存储空间都为 O ( 1 ) O(1) O(1)。