【链表】剑指 Offer 35. 复杂链表的复制

题目:

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

 

示例 :

 

 

 

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

 解答:

方法一:

这个复制过程可以分成两步:第一步是复制原始链表上的每个节点,并用next指针相连; 第二步是设置每个节点的random指针。

第一步的实现较为简单,第二步,对于一个n个节点的链表,定位每个节点的random 指针都需要从链表头节点开始经过O(n)步才能找到,因此这种方法总的时间复杂度是O(n^2)

/*
// 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 null;

        Node res = new Node(head.val);
        Node pre = res;
        map.put(head,res);

        Node p = head.next;
        while(p!=null){
            pre.next = new Node(p.val);
            pre = pre.next;

            map.put(p,pre);

            p = p.next;

           
        }
        pre.next = null;

        p = head;
        pre = res;
        while(p!=null){
            if(p.random!=null)
                pre.random = map.get(p.random);
            else
                pre.random = null;
            p = p.next;
            pre = pre.next;
        }
        
        return res;
    }

    public Node searchNode(Node dest, Node head, Node res){

        Node result = res;
        Node p = head;
        while(p!=dest){
            p = p.next;
            result = result.next;
        }
        return result;
    }
}

方法一的改进:

使用HashMap来简化搜索过程,使这个过程时间复杂度变为O(1)

还是分为两步:第一步仍然是将原始链表上的每个节点 N复制为N',然后把这些创建出来的节点N’连接起来。
同时我们把<N,N'>的配对信息放到一个HashMap<Node,Node> map中;
第二步设置每个节点的random指针:如果在原始链表中节点 N的random指针指向节点 S,那么在复制链表中,对应的 N'节点应该指向 S'。

/*
// 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 null;

        Node res = new Node(head.val);
        Node pre = res;
        map.put(head,res);

        Node p = head.next;
        while(p!=null){
            pre.next = new Node(p.val);
            pre = pre.next;

            map.put(p,pre);

            p = p.next;

           
        }
        pre.next = null;

        p = head;
        pre = res;
        while(p!=null){
            if(p.random!=null)
                pre.random = map.get(p.random);
            else
                pre.random = null;
            p = p.next;
            pre = pre.next;
        }
        
        return res;
    }

    public Node searchNode(Node dest, Node head, Node res){

        Node result = res;
        Node p = head;
        while(p!=dest){
            p = p.next;
            result = result.next;
        }
        return result;
    }
}

方法二:

在不使用辅助空间的情况下实现O(n)的时问效率。

第一步:复制节点:将原始链表的任意节点 N复制为新节点N',再把N'连接到 N的后面。
即如果原始链表为A->B->C->D 则复制过后为A->A'->B->B'->C->C'->D->D'
第二步:  确定每个新增节点N'的random指针指向
显然,如果原始链表上的节点 N 的random指针指向节点S,则它对应的复制节点N'的random指针指向节点S的复制节点S',也就是当前节点S的下一个节点。
第三步:  把这个长链表拆分成两个链表,把奇数位置的节点连接起来就是原始链表,把偶数位置的节点连接起来就是复制出来的链表。

//推荐双百方法二:不需要辅助空间,但是需要额外将两个链表进行拆分,但理解难度较大
    public Node copyRandomList2(Node head) {
        if(head==null) return null;
        copy2(head);
        randomAdd2(head);
        return build2(head);
    }
    public void copy2(Node head){
         while(head!=null){
            Node copy = new Node(head.val);
            copy.next = head.next;
            head.next =copy;
            head = copy.next;
        }
    }
    public void randomAdd2(Node head){
        while(head!=null){
           if(head.random!=null) head.next.random = head.random.next;
           head=head.next.next; 
        }
    }
    public Node build2(Node head){
        //将链表拆成两个,注意要恢复原有的链表
        Node res = head.next;
        Node tmp = res;

        head.next = head.next.next;//这一步不可缺少,保证第一个复制节点对N N'的分离操作
        head = head.next;
        while(head!=null){
            tmp.next = head.next;
            head.next = head.next.next;
            tmp=tmp.next;
            head = head.next;
         }
        return res;
    }

 

posted @ 2020-09-14 20:38  3KBLACK  阅读(62)  评论(0)    收藏  举报