[路飞]_leetcode刷题_剑指 Offer 35. 复杂链表的复制

532 阅读2分钟

题目

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

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

分析:

这题难点就在于如何去复制节点的random指针,你直接去拷贝一个random,会面临不知道random是否有创建。
那么想知道random是否有创建,可以用一个哈希表来存一个当前节点与拷贝节点的映射。

思路1:

哈希表+迭代

  1. 先遍历原链表,复制所有的节点,并存入哈希表,key是原节点,value是复制的节点,next和random先都暂时复制为null
  2. 再遍历原链表,为复制的节点去赋值next和random指针,指针的来源就是,【原节点所指向的next和random节点,在hash表里映射对应的复制的节点

具体代码如下:

/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function(head) {
    let cur = head;
    let hashMap = new Map();

    while(cur){
        hashMap.set(cur,new Node(cur.val,null,null));
        cur = cur.next;
    }

    cur = head;
    while(cur){
        hashMap.get(cur).next = cur.next ? hashMap.get(cur.next) : null;
        hashMap.get(cur).random = cur.random ? hashMap.get(cur.random) : null;
        cur = cur.next;
    }
    return hashMap.get(head);
}

思路2:

拼接+剪切

复制一套链接节点,让后让新旧节点依次交错的排列在一起,那么我们访问找新节点random的时候,可以去找新节点的前一个原节点random的next

  1. 遍历原链表,遍历每一个节点的时候,复制一个新节点,然后将新节点放在原节点后,即cur.next = newNode,newNode.next = cur.next.next;
  2. 遍历原链表,将原节点的random所指向节点的next复制给新节点,也即cur.next.random = cur.random.next,这里要做一下cur.random非空判断
  3. 遍历原链表,将新旧链表的链接切断。

代码如下:

/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function(head) {
    if(head==null)return head;
    let cur = head;
    while(cur){
        let tmp = new Node(cur.val,null,null);
        tmp.next = cur.next;
        cur.next = tmp;
        cur = cur.next.next;
    }

    cur = head;
    while(cur){
        cur.next.random = cur.random ? cur.random.next : null;
        cur = cur.next.next;
    }

    cur = head.next;
    let pre = head,res = head.next;
    while(cur.next){
        pre.next = pre.next.next;
        cur.next = cur.next.next;
        pre = pre.next;
        cur = cur.next;
    }
    pre.next = null;
    return res
}

思路3:

哈希表+递归

这个方法由于有递归,稍微难理解一点,但是最简洁的。

  1. 定义递归函数,入参是原节点和哈希表,出参是新节点
  2. 判断入参的这个原节点,是否有创建新节点,有则直接返回,没有则开始创建
  3. 复制这个原节点的创建一个新节点,nex和random先赋值null,并以原节点为key,新节点为value存入哈希表
  4. 为这个新节点复制next指针,值为递归调用自身去哈希表里寻找或者创造。
  5. 为这个新节点复制random指针,值为递归调用自身去哈希表里寻找或者创造。

大家可以自己写个简单的demo一步一步去消化一下

代码如下:

/**
 * @param {Node} head
 * @return {Node}
 */
var copyRandomList = function(head,cacheNode = new Map()) {
    if(head==null)return head;
    if(!cacheNode.get(head)){
        cacheNode.set(head,{val:head.val})
        cacheNode.get(head).next = copyRandomList(head.next,cacheNode)
        cacheNode.get(head).random = copyRandomList(head.random,cacheNode)
    }
    return cacheNode.get(head);
}