|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[652. 寻找重复的子树](https://leetcode.cn/problems/find-duplicate-subtrees/solution/by-ac_oier-ly58/)** ,难度为 **中等**。 |
| 4 | + |
| 5 | +Tag : 「二叉树」、「哈希表」、「DFS」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +给定一棵二叉树 `root`,返回所有重复的子树。 |
| 10 | + |
| 11 | +对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。 |
| 12 | + |
| 13 | +如果两棵树具有相同的结构和相同的结点值,则它们是重复的。 |
| 14 | + |
| 15 | +示例 1: |
| 16 | + |
| 17 | +``` |
| 18 | +输入:root = [1,2,3,4,null,2,4,null,null,4] |
| 19 | + |
| 20 | +输出:[[2,4],[4]] |
| 21 | +``` |
| 22 | +示例 2: |
| 23 | + |
| 24 | +``` |
| 25 | +输入:root = [2,1,1] |
| 26 | + |
| 27 | +输出:[[1]] |
| 28 | +``` |
| 29 | +示例 3: |
| 30 | + |
| 31 | +``` |
| 32 | +输入:root = [2,2,2,3,null,3,null] |
| 33 | + |
| 34 | +输出:[[2,3],[3]] |
| 35 | +``` |
| 36 | + |
| 37 | +提示: |
| 38 | +* 树中的结点数在 $[1,10^4]$ 范围内。 |
| 39 | +* $-200 <= Node.val <= 200$ |
| 40 | + |
| 41 | +--- |
| 42 | + |
| 43 | +### DFS + 哈希表 |
| 44 | + |
| 45 | +设计递归函数 `String dfs(TreeNode root)`,含义为返回以传入参数 `root` 为根节点的子树所对应的指纹标识。 |
| 46 | + |
| 47 | +对于标识的设计只需使用 `"_"` 分割不同的节点值,同时对空节点进行保留(定义为空串 `" "`)即可。 |
| 48 | + |
| 49 | +使用哈希表记录每个标识(子树)出现次数,当出现次数为 2ドル$(首次判定为重复出现)时,将该节点加入答案。 |
| 50 | + |
| 51 | +Java 代码: |
| 52 | +```Java |
| 53 | +class Solution { |
| 54 | + Map<String, Integer> map = new HashMap<>(); |
| 55 | + List<TreeNode> ans = new ArrayList<>(); |
| 56 | + public List<TreeNode> findDuplicateSubtrees(TreeNode root) { |
| 57 | + dfs(root); |
| 58 | + return ans; |
| 59 | + } |
| 60 | + String dfs(TreeNode root) { |
| 61 | + if (root == null) return " "; |
| 62 | + StringBuilder sb = new StringBuilder(); |
| 63 | + sb.append(root.val).append("_"); |
| 64 | + sb.append(dfs(root.left)).append(dfs(root.right)); |
| 65 | + String key = sb.toString(); |
| 66 | + map.put(key, map.getOrDefault(key, 0) + 1); |
| 67 | + if (map.get(key) == 2) ans.add(root); |
| 68 | + return key; |
| 69 | + } |
| 70 | +} |
| 71 | +``` |
| 72 | +Typescript 代码: |
| 73 | +```Typescript |
| 74 | +let ans: Array<TreeNode> |
| 75 | +let map: Map<string, number> |
| 76 | +function findDuplicateSubtrees(root: TreeNode | null): Array<TreeNode | null> { |
| 77 | + ans = new Array<TreeNode>() |
| 78 | + map = new Map<string, number>() |
| 79 | + dfs(root) |
| 80 | + return ans |
| 81 | +}; |
| 82 | +function dfs(root: TreeNode | null): string { |
| 83 | + if (root == null) return " " |
| 84 | + let key = root.val + "_" |
| 85 | + key += dfs(root.left) |
| 86 | + key += dfs(root.right) |
| 87 | + if (!map.has(key)) map.set(key, 1) |
| 88 | + else map.set(key, map.get(key) + 1) |
| 89 | + if (map.get(key) == 2) ans.push(root) |
| 90 | + return key |
| 91 | +} |
| 92 | +``` |
| 93 | +* 时间复杂度:`DFS` 过程复杂度为 $O(n),ドル对于每个子树需要构造出与子树同等规模的字符串,复杂度为 $O(n)$。整体复杂度为 $O(n^2)$ |
| 94 | +* 空间复杂度:$O(n)$ |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +### 最后 |
| 99 | + |
| 100 | +这是我们「刷穿 LeetCode」系列文章的第 `No.652` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 |
| 101 | + |
| 102 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 103 | + |
| 104 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 105 | + |
| 106 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 107 | + |
0 commit comments