复杂链表的复制

858 阅读3分钟

1、题目描述

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

2、思路分析

方法一:回溯+哈希(虽然我也没太看懂哪里体现出了回溯的思想)

这里我倒是没看出回溯提现在哪里,更多的应该是一个递归的思想,首先对于当前节点进行拷贝,然后利用递归对于当前节点的后继节点和随机节点进行拷贝,最后将拷贝完成的新节点返回,即是拷贝完成的链表。

具体实现步骤如下:

  • 利用哈希表存储新节点的创建情况,原来节点作为键,新节点为value
  • 检查「当前节点的后继节点」和「当前节点的随机指针指向的节点」的创建情况。如果这两个节点中的任何一个节点的新节点没有被创建,我们都立刻递归地进行创建
  • 当我们拷贝完成,回溯到当前层时,我们即可完成当前节点的指针赋值
  • 注意一个节点可能被多个其他节点指向,因此我们可能递归地多次尝试拷贝某个节点,为了防止重复拷贝,我们需要首先检查当前节点是否被拷贝过,如果已经拷贝过,我们可以直接从哈希表中取出拷贝后的节点的指针并返回即可。

方法二:迭代+节点拆分

可以将链表中的每一个节点拆分成两个相邻的节点,例如对于链表A->B->C,可以将其拆分成A->A'->B->B'->C->C',其中任意一个节点S,S'代表其拷贝节点。

然后我们就可以找到S'节点的随机指针应该指向的节点,是原节点S的随机指针指向的节点T的后继节点T',需要注意的是原节点的随机指针可能为空。

当我们完成了拷贝节点的随机指针的赋值,我们只需要将这个链表按照原节点与拷贝节点的种类进行拆分即可,只需要遍历一次。同样需要注意最后一个拷贝节点的后继节点为空,我们需要特别判断这种情况。

3、代码实现

回溯方法实现

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    Map<Node,Node> map = new HashMap<>();
    public Node copyRandomList(Node head) {
        if(head == null){
            return head;
        }
        if(!map.containsKey(head)){
            Node headNew = new Node(head.val);
            map.put(head,headNew);
            headNew.next = copyRandomList(head.next);
            headNew.random = copyRandomList(head.random);
        }
        return map.get(head);
    }
}

节点拆分方法实现

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
       if(head == null){
           return head;
       }
       for(Node node = head;node != null;node = node.next.next){
           Node nodeNew = new Node(node.val);
           nodeNew.next = node.next;
           node.next = nodeNew;
       }
       for(Node node = head;node != null;node = node.next.next){
           Node nodetemp = node.next;
           nodetemp.random = (node.random != null) ? node.random.next : null;
       }
       Node headNew = head.next;
       for(Node node = head;node != null;node = node.next){
           Node nodeNew = node.next;
           node.next = node.next.next;
           nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;
       }
       return headNew;
    }
}