参考自:《剑指Offer——名企面试官精讲典型编程题》
题目:复杂链表的复制
请实现复制一个复杂链表的函数。在复杂链表中,每个结点除了有一个next指针指向下一个结点外,还有一个额外指针random指向链表中的任意结点或者null。
主要思路:
分三步:
第一步:复制每个旧节点,使得新节点A’在旧节点A后面(A ->A’ ->B)。
第二步:根据旧节点的额外节点,设置新节点对应的额外节点。其中,新额外节点 = 旧额外节点的下一个节点。
第三步:拆分前两步生成的链表成2个链表,使得新节点和旧节点分离。每次旧节点移动2步,新节点就是旧节点的前一个节点和后一个节点,然后连接新节点和它的下一个节点。
例如:
A ->A’ ->B ->B’ ->C ->C’
A’.next = B.next(其中B.next 即为B’)
关键点:分步,先复制后拆分
时间复杂度:O(n)
public class CloneLinkedList
{
public static void main(String[] args)
{
RandomListNode head = getTestData();
RandomListNode newHead = clone(head);
while (newHead != null)
{
if (newHead.random != null)
{
System.out.printf("节点值:%s 额外节点值:%s", newHead.label, newHead.random.label);
} else
{
System.out.printf("节点值:%s", newHead.label);
}
System.out.println();
newHead = newHead.next;
}
}
private static RandomListNode getTestData()
{
RandomListNode head = new RandomListNode(1);
RandomListNode head2 = new RandomListNode(2);
RandomListNode head3 = new RandomListNode(3);
RandomListNode head4 = new RandomListNode(4);
head.next = head2;
head2.next = head3;
head3.next = head4;
head2.random = head4; //额外节点
return head;
}
private static RandomListNode clone(RandomListNode pHead)
{
cloneNodes(pHead);
connectSibling(pHead);
return reconnectNode(pHead);
}
//复制每个旧节点
private static void cloneNodes(RandomListNode pHead)
{
RandomListNode oldNode = pHead;
//复制每个旧节点,使得新节点A'在旧节点A后面
//A ->A' ->B
while (oldNode != null)
{
RandomListNode newNode = new RandomListNode(oldNode.label);
RandomListNode oldNext = oldNode.next;
newNode.next = oldNext;
oldNode.next = newNode;
oldNode = oldNext;
}
}
//设置新节点的额外节点
private static void connectSibling(RandomListNode pHead)
{
RandomListNode oldNode = pHead;
//根据旧节点的额外节点,设置新节点对应的额外节点。
while (oldNode != null)
{
RandomListNode newNode = oldNode.next;
RandomListNode oldRandom = oldNode.random; //旧节点指向的额外节点
if (oldRandom != null)
{
//新额外节点 = 旧额外节点的下一个节点
newNode.random = oldRandom.next;
}
oldNode = newNode.next;
}
}
/**
* 长链表拆成新旧2个链表
*
* @param pHead
* @return
*/
private static RandomListNode reconnectNode(RandomListNode pHead)
{
RandomListNode oldNode = pHead;
RandomListNode newHead = null;
RandomListNode newNode = null;
//获取头指针
if (pHead != null)
{
newHead = pHead.next;
newNode = newHead;
oldNode = newNode.next;
}
while (oldNode != null)
{
RandomListNode newNext = oldNode.next;
//连接新节点的下一个节点
newNode.next = newNext;
newNode = newNext;
//旧节点移动2步
if (newNext == null) break;
oldNode = newNext.next;
}
return newHead;
}
}