Reputation: 8297
class Solution:
def findDuplicateSubtrees(self, root):
self.res = []
self.dic = {}
self.dfs(root)
return self.res
def dfs(self, root):
if not root: return '#'
tree = self.dfs(root.left) + self.dfs(root.right) + str(root.val)
if tree in self.dic and self.dic[tree] == 1:
self.res.append(root)
self.dic[tree] = self.dic.get(tree, 0) + 1
return tree
This is a solution for getting all duplicate subtrees given a binary tree.
I am not sure what tree = self.dfs(root.left) + self.dfs(root.right) + str(root.val)
is trying to give.
I know it's trying to do a postorder traversal, but how does this part actually work?
It would be great if anyone can follow through this code. Thanks.
Upvotes: 0
Views: 41
Reputation: 1653
Basically, the variable tree
can be regarded as an encoding string for each subtree. And we use a global dict self.dic
to memorize those encoded strings.
An examples:
A
B C
D D E B
D D
In level order, the binary tree can be descripted as [[A], [B, C], [D, D, E, B], [#, #, #, #, #, #, D, D]]
, so we have at least two duplicate subtrees as [[B], [D, D]]
and [D]
Follow the code, we have
dfs(A)
dfs(B)
dfs(D) *save ##D, return ##D
dfs(D) *find ##D, get one subtree, return ##D
*save ##D##DB, return ##D##DB
dfs(C)
...
Upvotes: 1
Reputation: 198324
Recursion is best untangled from bottom up.
"#"
.1
would return "##1"
(as it has two non-node children).3
with two leaf daughters 1
and 2
would return ##1##23
. "##1"
is the dfs
of the left daughter, "##2"
is the dfs
of the right daughter, and "3"
is the stringified current node's value.In this way, assuming there's no node with value 23
and another with empty string value, you can see that if two different nodes produce ##1##23
, they are a duplicate subtree. It would be much more robust if there were some additional separators employed (e.g. a semicolon at the end of that line would produce "##1;##2;3;
), which would be sufficient to make it a bit more readable and less ambiguous. Even safer (but slower) if done with lists.
Upvotes: 1