[路飞]_前端算法第四十二弹-剑指 Offer 35. 复杂链表的复制

98 阅读2分钟

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:

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]

示例 3:

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]

示例 4:

输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

分析

简单来说就是进行三次遍历,第一次遍历将原链表的长度*2,即原链表为A→B→C,新链表为A→a→B→b→C→c。将原节点ABC拷贝至新节点abc,这样,我们可以通过第二次遍历直接找到每一个新节点的随机指针,将其原本指向的原节点ABC更改为指向abc,此时记得要判断null。

第三次遍历则是将原节点与新节点进行拆分。这样新节点便组成了我们想要的全新的链表。

var copyRandomList = function(head) {
    if (head === null) {
        return null;
    }
		// 因为注入了新节点,所以原节点的next此时变成了next.next
    for (let node = head; node !== null; node = node.next.next) {
				// 创建新节点,也是深拷贝的过程。
        const nodeNew = new Node(node.val, node.next, null);
				// 原节点的下一个节点指向新节点,新节点的下一个结点是原节点的原下一个节点
        node.next = nodeNew;
    }
		// 第二次遍历,更改random的指向,每次循环都是遍历原节点所以是next.next
    for (let node = head; node !== null; node = node.next.next) {
				// 找到新节点
        const nodeNew = node.next;
				// 新节点的random指向新节点,注意判断null
        nodeNew.random = (node.random !== null) ? node.random.next : null;
    }
		// 拆分新老节点。
    const headNew = head.next;
    for (let node = head; node !== null; node = node.next) {
        const nodeNew = node.next;
        node.next = node.next.next;
        nodeNew.next = (nodeNew.next !== null) ? nodeNew.next.next : null;
    }
    return headNew;
};

欢迎建议讨论