剑指25.复杂链表的复制

题目描述

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
 

思路

思路1:先复制结点,用next链接,最后根据原始结点的random指针确定该random结点距离头结点的位置,从而对复制结点设置random指针。但是该思路对于n个结点的链表,定位每个节点的random都需要从链表头节点开始经过O(n)步才能找到,所以时间复杂度为O(n^2)。  (时间主要花费在定位节点的random上)
 
 
思路2:复制原始结点N创建N’,用next链接。将<N,N'>的配对信息存放入一个哈希表中;在设置random时,通过哈希表,只需要用O(1)的时间即可找到复制结点的random。该方法的时间复杂度为O(n),但空间复杂度为O(n)。        (相当于空间换时间)
 
 
思路3:不用辅助空间的情况下,实现O(n)的时间效率。该方法分为三个步骤。
第一步:复制原始链表的任意节点N并创建新节点N',再把N'链接到N的后面

第二步:把复制的节点的random指针指向被复制节点的random指针的下一个节点

第三步: 拆分成两个链表,奇数位置为原链表,偶数位置为复制链表,注意复制链表的最后一个结点的next指针不能跟原链表指向同一个空结点None,next指针要重新赋值None(判定程序会认定你没有完成复制)

 

解法1(对应思路3)

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        if (pHead == null) return null;
        cloneNodes(pHead);             // 复制节点
        connectRandomNodes(pHead);     // 设置random
        return reconnectNodes(pHead);  // 拆分长链表
    }
    // 第一步:复制每个结点,并插入到原始节点的后面
    private void cloneNodes(RandomListNode pHead){
        RandomListNode currentNode = pHead;
        while (currentNode != null){
            RandomListNode cloneNode = new RandomListNode(currentNode.label);
            cloneNode.next = currentNode.next;
            cloneNode.random = null;
            currentNode.next = cloneNode;

            currentNode = cloneNode.next;
        }
    }
    // 第二步:根据原节点的random,设置复制节点的random
    private void connectRandomNodes(RandomListNode pHead){
        RandomListNode currentNode = pHead;
        while (currentNode != null){
            if (currentNode.random != null)
                currentNode.next.random = currentNode.random.next; // 指向原始节点random指向的下一个节点
            currentNode = currentNode.next.next;
        }
    }
    // 第三步:将长链表拆分成原始链表和复制链表(根据奇偶位置)
    private RandomListNode reconnectNodes(RandomListNode pHead){
        RandomListNode currentNode = pHead;
        RandomListNode pCloneHead = pHead.next;
        while (currentNode != null){
            RandomListNode pCloneNode = currentNode.next;
            if (pCloneNode.next != null){
                currentNode.next = pCloneNode.next;
                pCloneNode.next = currentNode.next.next;
            }else{
                currentNode.next = null;
                pCloneNode.next = null;
            }
            currentNode = currentNode.next;
        }
        return pCloneHead;
    }
}

解法2(对应思路2)

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
import java.util.HashMap;
/*
   使用哈希表,时间复杂度O(N),额外空间复杂度O(N)
   需要2次遍历即可
 */
public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        if (pHead == null) return null;
        HashMap<RandomListNode,RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
        RandomListNode currentNode = pHead;
        // 第一次遍历,新建节点,将<N,N'>的配对信息放到Map中
        while (currentNode != null){
            map.put(currentNode, new RandomListNode(currentNode.label));
            currentNode = currentNode.next;
        }

        // 第二次遍历,设置复制节点的属性next和random
        currentNode = pHead;
        while (currentNode != null){
            RandomListNode cloneNode = map.get(currentNode);
            // 注意复制链表的最后一个结点的next指针不能跟原链表指向同一个空结点
            cloneNode.next = currentNode.next == null ? null : map.get(currentNode.next);
            cloneNode.random = currentNode.random == null ? null : map.get(currentNode.random);
            currentNode = currentNode.next;
        }
        return map.get(pHead);
    }
}
原文地址:https://www.cnblogs.com/HuangYJ/p/13504149.html