前端算法小白攻略11-leetcode(复制带随机指针的链表)

100 阅读3分钟

前言

如何复制一个链表,并且这个链表中的节点还带有随机指针,最后复制的链表还和原链表没有指针的指向关系?看这里,只需3步即可完成!

题目描述(题目略长懂得直接看思路)

复制带随机指针的链表 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。 random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。 你的代码 只 接受原链表的头节点 head 作为传入参数。

 

示例 1:

image.png

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

解题思路

  1. 利用题目Node函数复制带有随机指针的节点追加到每个原节点后(得到节点与原节点有相同的指向)
  2. 纠正随机指针的指向问题
  3. 就复制节点拆出来并且保持原有链表

开始解题

/**
 * // Definition for a Node.
 * function Node(val, next, random) {
 *    this.val = val;
 *    this.next = next;
 *    this.random = random;
 * };
 */

/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function(head) {
    if(!head) return null;
    let cur = head;
    let cNode = null; // while 循环外初始化复制节点,避免每次都声明
    while(cur) {
        let next = cur.next; // 保存cur.next不丢失
        cNode = new Node(cur.val,next,cur.random);// 复制原有节点
        cur.next = cNode; // cur连接复制的cNode节点,为什么没写cNode.next = cur.next? 因为在Node方法里已经做了这一步
        cur = next;
    } // 每个复制节点都会跟在原节点后面
    cur = head.next; // 让cur指向head的下一个节点,也就是复制节点,因为我们用从复制节点开始纠正随机指针
    while(cur) {
        cur.random && (cur.random = cur.random.next); // 随机指针指向的节点后也是有复制节点,如果cur有随机指针,我们就让cur.random指向原节点随机指针指向节点的复制节点即可
        (cur = cur.next) && (cur = cur.next); // 每间隔一位才是复制节点
    }
    let temp = head.next; // 保存一下head.next作为我们复制链表的头节点返回
    cur = head.next; // 操作cur指针拆出我们的复制链表
    while(cur.next) { // 当cur.next 为null也就是已经遍历到最后一个复制节点了
        let next = head.next.next; 
        let temp = cur.next.next;
        head.next = head.next.next; // 让head连接head的下下个节点
        cur.next = cur.next.next; // 让cur连接cur的下下个节点,cur与head间隔相连,拆成两条链表
        cur = temp;
        head = next;
    }
    head.next = null; // 复制节点是最后一个节点不用指向null,head为复制节点的前一个节点需要断开去指向null,拆解完毕
    return temp;
};