剑指Offer 35 - 复杂链表的复制

Posted xintangchn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指Offer 35 - 复杂链表的复制相关的知识,希望对你有一定的参考价值。

力扣链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/

题目描述

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

思路

很容易想到的步骤是首先复制简单链表,忽略random,然后再遍历一次链表复制random。但由于链表不支持随机存取,且Node是引用类型,如何在新链表中定位random就成为问题的关键。(例如在原链表中,head.random为第10个节点,我们就需要遍历完新链表的前十个节点,才能定位到newHead.random, 并且由于Node是引用类型,判断newHead.random和head.random一样也比较复杂)

有两种方法解决:

  • 法一:用哈希表存储原节点到复制节点的映射关系
  • 法二:复制所有节点,使得复制节点位于原始节点的下一个,形成位置上的映射关系

法一:

/**
 * // 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;
    
    const copyHead = new Node(head.val, null, null);
    
    //1. 复制节点,保存map
    let copyCur = copyHead;
    let cur = head;
    const map = new Map();
    while(cur){
        map.set(cur, copyCur);
        let copyNext = cur.next ? new Node(cur.next.val, null, null) : null;
        copyCur.next = copyNext;
        
        copyCur = copyCur.next;
        cur = cur.next;
    }
    
    //2.处理random
    cur = head;
    copyCur = copyHead;
    while(cur){
        if(cur.random){
            copyCur.random = map.get(cur.random);
        }
        cur = cur.next;
        copyCur = copyCur.next;
    }
    

    return copyHead;
};

易错:凡涉及node.next.val一定要考虑node.next为null的情况。

时间复杂度:O(N)

空间复杂度:O(N)

法二:

  1. 复制所有节点,新节点的random统一指向null。1->2->3->null 改为 1->1->2->2->3->3->null
  2. 处理新节点的random指针,指向原节点的random 的复制节点(即next节点)
  3. 分离原链表和复制链表,依次修改next指针

代码:

/**
 * // 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 original = head;
    
    //1. 复制节点
    while(original){
        let originalNext = original.next;
        let copy = new Node(original.val, originalNext, null);
        original.next = copy;
        
        original = original.next.next;
    }
    //2.处理random
    original = head;
    while(original){
        if(original.random){
            original.next.random = original.random.next;
        }
        
        original = original.next.next;
    }
    
    //3.分离链表
    original = head;
    let copyHead = head.next;
    while(original){
        let copy = original.next;
        original.next = copy.next;
        if(original.next){
            copy.next = original.next.next;
        }
        
        original = original.next;
    }
    
    return copyHead;
};

易错:同上,涉及.next.random / .next.val 一定注意判断对象是否可能为空。

时间复杂度:O(N)

空间复杂度:O(1)

以上是关于剑指Offer 35 - 复杂链表的复制的主要内容,如果未能解决你的问题,请参考以下文章

Java 剑指offer(35) 复杂链表的复制

剑指Offer35.复杂链表的复制

leetcode 剑指 Offer 35. 复杂链表的复制

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

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

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