一座魔法森林, 随机链接吧-复制一棵带有随机指针的二叉树

91 阅读2分钟

🌳 想象你的树是一座魔法森林

假设你有一座魔法森林,里面的每棵树都有一些奇怪的连接

  • 🌲 左孩子:指向自己的左边
  • 🌳 右孩子:指向自己的右边
  • 🎲 随机指针:随意指向森林中的某棵树(甚至可能是自己)

现在,你需要施展魔法,把这整片森林完整地复制一份,包括这些奇怪的连接方式!


解题思路(魔法步骤)

  1. 创建一本魔法书📖(HashMap)

    • 这本书会记录:原始树的节点 -> 新拷贝出来的节点 的映射关系。
    • 这样我们在遇到一个节点时,就知道是否已经复制过了。
  2. 使用DFS进行复制🧙‍♂️

    • 每次遇到一个新节点:

      • 复制它,并存入魔法书
      • 递归地处理它的左、右、随机指针
      • 更新新节点的指针指向
  3. 返回新复制的根节点🌱


📌 代码java


public TreeNode copyTree(TreeNode root) {
    Map<TreeNode, TreeNode> copiedMap = new HashMap<>();
    dfs(root, copiedMap);
    return copiedMap.get(root);
}

private void dfs(TreeNode root, Map<TreeNode, TreeNode> copiedMap) {
    if (copiedMap.containsKey(root)) return; // 如果已经复制过,直接返回

    // 创建新节点
    TreeNode copiedRoot = new TreeNode(root.val);
    copiedMap.put(root, copiedRoot); // 记录映射关系

    // 递归复制左孩子
    if (root.left != null) {
        dfs(root.left, copiedMap);
        copiedRoot.left = copiedMap.get(root.left);
    }

    // 递归复制右孩子
    if (root.right != null) {
        dfs(root.right, copiedMap);
        copiedRoot.right = copiedMap.get(root.right);
    }

    // 递归复制随机指针
    if (root.random != null) {
        dfs(root.random, copiedMap);
        copiedRoot.random = copiedMap.get(root.random);
    }
}

🎯 代码解读(通俗版)

  1. 我先翻开魔法书📖,看看这个节点有没有被记录过

    • 如果已经复制过,那就直接返回,不重复造树。
  2. 如果这个节点没见过,那我就施展魔法🪄,复制它

    • 创建一个新节点(跟原来的值一样)。
    • 存进魔法书,方便后续查找。
  3. 然后去复制它的“左边”“右边”和“随机指针”

    • 先去左边看看👈,如果有左孩子,就递归地复制。
    • 再去右边瞧瞧👉,如果有右孩子,也递归地复制。
    • 最后看看这个节点的“随机指针”🎲指向哪里,复制后也连上。
  4. 所有节点都处理完后,返回新树的根节点🌱!


💡 为什么要用 HashMap?

你可能会问:“为什么要用 HashMap 记录已经复制过的节点?”
原因是:

  • 防止重复复制:如果某个节点已经被复制过,就直接复用它,避免陷入无限递归。
  • 处理“随机指针” :树的 random 指针可能指向任意一个已经遍历过的节点,如果不记录它的位置,后续查找就会很麻烦。

🏆 总结

✅ 这道题的核心思想是用哈希表(Map)来记录原节点和新节点的映射关系,然后递归地复制整棵树
每个节点最多访问三次(左、右、随机),时间复杂度是 O(N),空间复杂度也是 O(N)(存储 Map)
✅ 这样,我们就成功复制了一片一模一样的魔法森林🌲🌳🎲