leetcode
leetcode 1351 ~ 1400
克隆含随机指针的二叉树

克隆含随机指针的二叉树

难度:

标签:

题目描述

代码结果

运行时间: 101 ms, 内存: 18.2 MB


/*
 * 思路:
 * 1. 使用深度优先搜索(DFS)的方法来遍历原树。
 * 2. 使用一个HashMap来存储原节点和对应的新节点之间的映射关系,以便处理随机指针。
 * 3. 首先复制树的节点结构,然后根据映射关系复制随机指针。
 * 由于Java Stream主要用于处理集合,不能直接应用于树结构的深度拷贝,此处依然采用常规递归方式。
 */
import java.util.HashMap;

class Node {
    int val;
    Node left;
    Node right;
    Node random;
    Node(int x) { val = x; }
}

public class SolutionStream {
    public Node copyRandomBinaryTree(Node root) {
        if (root == null) return null;
        HashMap<Node, Node> map = new HashMap<>();
        return cloneNodes(root, map);
    }

    private Node cloneNodes(Node root, HashMap<Node, Node> map) {
        if (root == null) return null;
        if (map.containsKey(root)) return map.get(root);

        Node newNode = new Node(root.val);
        map.put(root, newNode);
        newNode.left = cloneNodes(root.left, map);
        newNode.right = cloneNodes(root.right, map);
        newNode.random = map.get(root.random);  // 处理随机指针
        return newNode;
    }
}

解释

方法:

该题解采用了深度优先搜索(DFS)的方法来复制含随机指针的二叉树。使用一个哈希表`seen`来存储已经被访问和复制过的原始节点与其对应的复制节点的映射,以防止重复处理节点并处理可能的循环引用。对于每个被访问的节点,如果它已经在`seen`中,直接返回其对应的复制节点。如果不在`seen`中,创建一个新的复制节点,并将其加入`seen`,然后递归地复制当前节点的左子节点、右子节点和随机指针所指向的节点。最后返回复制的根节点。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么选择深度优先搜索(DFS)而不是广度优先搜索(BFS)来实现这个克隆功能?
在克隆含随机指针的二叉树问题中,深度优先搜索(DFS)的选择优于广度优先搜索(BFS)出于几个理由。首先,DFS允许我们自然地沿着树的分支深入,直到叶子节点,然后回溯,这种方式非常适合递归实现,代码更简洁。其次,DFS优先创建所有必需的节点,确保当随机指针需要连接到某个特定节点时,该节点已经被创建并可以直接引用。这在BFS中也可以实现,但管理节点创建和它们随机指针的关联通常更复杂,需要额外的数据结构如队列来维护节点的层级状态。
🦆
在哈希表`seen`中,键和值分别表示什么?具体如何实现节点的映射?
在哈希表`seen`中,键是原始树中的节点,而值是对应的复制树中的节点。通过这种方式,每当访问到一个原始节点时,我们可以检查该节点是否已经被复制。如果已经存在于哈希表中,直接使用映射的复制节点,避免重复创建和递归,这也帮助处理了循环引用的情况。具体实现时,当访问一个节点并决定复制它时,我们创建一个新的节点并将其加入到`seen`中,这样任何后续对原节点的引用都会直接转向已创建的复制节点。
🦆
如何处理随机指针所指向的节点可能为空的情况?
随机指针指向的节点可能为空是一个边界条件,必须在实现中显式处理。在深度优先搜索的递归函数`dfs`中,当访问到一个节点时,首先检查这个节点是否为`None`。如果是,递归函数直接返回`None`。这保证了即使随机指针指向`None`,复制过程也能正确地将复制节点的随机指针设置为`None`。这样的处理确保了复制的树结构和原始树在随机指针的空指向上保持一致。

相关问题