652. Find Duplicate Subtrees

64 阅读2分钟

image.png

image.png

方法1 :O(N^2) 序列化

  • 相同的子树会被序列化成相同的子串;
  • 不同的子树会被序列化成不同的子串。
class Solution {
    // <节点为root的树的序列化字符串,节点>
    Map<String, TreeNode> map = new HashMap<>();
    List<TreeNode> res = new ArrayList<>();
    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        dfs(root);
        return res;
    }

    // 返回当前树的序列化结果
    public String dfs(TreeNode node) {
        if (node == null) {
            return "";
        }
        // 序列化当前树,这一步需要O(n)
        String str = node.val + 
              "(" + dfs(node.left) + ")(" + dfs(node.right) + ")";

        if (map.containsKey(str)) {
            if (!res.contains(map.get(str))) {
                res.add(map.get(str));
            }
        } else {
            map.put(str, node);
        }

        return str;
    }
}

方法2 :O(N) 序列化优化

  • 对于每一个不同的子树,在DFS时可以生成唯一的序号idx
  • 判断子树是否重复:因为自底向上遍历,所以对于每个节点,可以获得其左右子树对应的唯一序号idx,这个节点的val和其左右子树的序号idx可以生成字符串标志flag"root_val,left_idx,right_idx",如果字符串在哈希Map中出现过,就说明当前子树重复;如果字符串没在哈希Map中出现过,就将<字符串,未使用过的idx>存入哈希Map。
  • 递归返回值:当前节点对应二叉树的唯一序号idx

如果dfs不返回idx而是返回当前子树字符串标志flag,而每个子树flag就从"root_val,left_idx,right_idx"变成了"root_val,left_flag,right_flag", 这样就是官方题解的方法1,每个字符串标志就是当前二叉树的序列化。第n个节点生成字符串的时间从O(1)变成O(n),那么总时间复杂度就变成了O(n2)

class Solution {
    int index = 0; // index表示不同子树的数量
    List<TreeNode> res = new ArrayList<>();
    // <节点id,<节点,节点index>>
    Map<String, Pair<TreeNode, Integer>> map = new HashMap<>();
    public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
        dfs(root);
        return res;
    }

    // dfs,返回一颗树的序号index,
    public int dfs(TreeNode root) {
        if (root == null) {
            return 0;
        }
        // id用于标识一棵树,相同的树id一样
        String id = root.val + "-" + dfs(root.left) + "-" + dfs(root.right);

        // 遍历到了相同的树
        if (map.containsKey(id)) {
            TreeNode node = map.get(id).getKey();
            if (!res.contains(node)) {
                res.add(node);// 避免重复添加
            }
            return map.get(id).getValue(); // 返回index
        } else {
            index++;
            map.put(id, new Pair<TreeNode, Integer>(root, index));
            return index;
        }
    }
}