138. 复制带随机指针的链表

562 阅读2分钟

题目介绍

力扣138题:leetcode-cn.com/problems/co…

image.png

image.png

分析

题目要求我们复制一个长度为 n 的链表,该链表除了每个节点有一个指针指向下一个节点外,还有一个额外的指针指向链表中的任意节点或者 null,如下图所示:

image.png

如何去复制一个带随机指针的链表?

首先我们可以忽略 random 指针,然后对原链表的每个节点进行复制,并追加到原节点的后面,而后复制 random 指针。最后我们把原链表和复制链表拆分出来,并将原链表复原。

图示过程如下:

1、在每个节点的后面加上它的复制,并将原链表和复制链表连在一起。

image.png

2、 从前往后遍历每一个原链表节点,对于有 random 指针的节点 p,我们让它的 p->next->random = p->random->next,这样我们就完成了对原链表 random 指针的复刻。

image.png

3、最后我们把原链表和复制链表拆分出来,并将原链表复原。

image.png

具体过程如下:

  • 1、定义一个 p 指针,遍历整个链表,复制每个节点,并将原链表和复制链表连在一起。
  • 2、再次遍历整个链表,执行 p->next->random = p->random->next,复制 random 指针。
  • 3、定义虚拟头节点 dummy 用来指向复制链表的头节点, 将两个链表拆分并复原原链表。

代码如下:

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

        //复制每个节点,并将原链表和复制链表连在一起。
        for(Node p = head; p != null; p = p.next.next) {
            Node q = new Node(p.val);
            q.next = p.next;
            p.next = q;
        }

        //复制random指针
        for(Node p = head; p != null; p = p.next.next) {
            if(p.random != null) {
                p.next.random = p.random.next;
            }         
        }

        //拆分两个链表,并复原原链表,哑结点
        Node dummy = new Node(-1);
        Node cur = dummy;
        for(Node p = head; p != null; p = p.next) {
            Node q = p.next;
            cur.next = q;
            cur = cur.next;
            p.next = q.next;
        }
        return dummy.next;
    }
}

时间复杂度分析:  O(n),其中 n 是链表的长度。

空间复杂度分析:  O(1)。