题目:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
节点定义如下:
struct RandomListNode
{
int value;
RandomListNode* next;
RandomListNode* random ;
RandomListNode():next(nullptr),random (nullptr) { }
};
思路一:
我们分为两步:
1.复制原始链表上每个节点N创建N*,然后把这些穿件出来的节点用next连接起来。同时我们把(N,N*)的配对信息放到一个哈希表中;
2.设置复制链表上每个节点的rand。
时间复杂度O(n),空间复杂度O(n)。
java参考代码如下:
public static class Node{
int value;
Node next;
Node rand;
public Node(int val){
this.value=val;
this.next=null;
this.rand=null;
}
}
//
public static Node copyListWithRand1(Node head){
if(head==null) return null;
HashMap<Node,Node> map=new HashMap<>();
Node cur=head;
while (cur!=null){
map.put(cur,new Node(cur.value));//放入的是遍历到的节点指针和副本。
cur=cur.next;
}
cur=head;
while (cur!=null){
map.get(cur).next=map.get(cur.next);
map.get(cur).rand=map.get(cur.rand);
cur=cur.next;
}
return map.get(head);
}
思路二:
分三步:
第一步:复制每个节点,如:复制节点A得到A1,将A1插入节点A后面;
第二步:遍历链表,A1->random = A->random->next;
第三步:将链表拆分成原链表和复制后的链表。
基于以上思路,Java参考代码如下:
package chapter4;
import java.util.HashMap;
public class P187_CopyComplexList {
public static class Node{
int value;
Node next;
Node rand;
public Node(int val){
this.value=val;
this.next=null;
this.rand=null;
}
}
public static void printRandLinkedList(Node head) {
Node cur = head;
System.out.print("order: ");
while (cur != null) {
System.out.print(cur.value + " ");
cur = cur.next;
}
System.out.println();
cur = head;
System.out.print("rand: ");
while (cur != null) {
System.out.print(cur.rand == null ? "- " : cur.rand.value + " ");
cur = cur.next;
}
System.out.println();
}
public static Node copyListWithRand2(Node head) {
if (head == null) {
return null;
}
Node cur = head;
Node next = null;
// copy node and link to every node
while (cur != null) {
next = cur.next;
cur.next = new Node(cur.value);
cur.next.next = next;
cur = next;
}
cur = head;
Node curCopy = null;
// set copy node rand
while (cur!=null){
cur.next.rand=cur.rand!=null?cur.rand.next:null;//注意 cur.rand为空的情况
cur=cur.next.next;
}
Node res = head.next;
cur = head;
// split
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
cur.next = next;
curCopy.next = next != null ? next.next : null;
cur = next;
}
return res;
}
public static void main(String[] args) {
Node head = null;
Node res1 = null;
Node res2 = null;
printRandLinkedList(head);
res1 = copyListWithRand1(head);
printRandLinkedList(res1);
res2 = copyListWithRand2(head);
printRandLinkedList(res2);
printRandLinkedList(head);
System.out.println("=========================");
head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
head.next.next.next.next = new Node(5);
head.next.next.next.next.next = new Node(6);
head.rand = head.next.next.next.next.next; // 1 -> 6
head.next.rand = head.next.next.next.next.next; // 2 -> 6
head.next.next.rand = head.next.next.next.next; // 3 -> 5
head.next.next.next.rand = head.next.next; // 4 -> 3
head.next.next.next.next.rand = null; // 5 -> null
head.next.next.next.next.next.rand = head.next.next.next; // 6 -> 4
printRandLinkedList(head);
res1 = copyListWithRand1(head);
printRandLinkedList(res1);
res2 = copyListWithRand2(head);
printRandLinkedList(res2);
printRandLinkedList(head);
System.out.println("=========================");
}
}
注意点见代码注解部分。
基于以上思路,C++参考代码如下:
class Solution
{
public:
RandomListNode* Clone(RandomListNode* pHead)
{
CloneNodes(pHead);
ConnectRandomNodes(pHead);
return ReconnectNodes(pHead);
}
//第一步
void CloneNodes(RandomListNode* pHead)
{
RandomListNode* pNode = pHead;
while(pNode != nullptr)
{
RandomListNode* pCloned = new RandomListNode(pNode->label);
pCloned->next = pNode->next;
pCloned->random = nullptr;
pNode->next = pCloned;
pNode = pCloned->next;
}
}
//第二步
void ConnectRandomNodes(RandomListNode* pHead)
{
RandomListNode* pNode = pHead;
while(pNode != nullptr)
{
RandomListNode* pCloned = pNode->next;
if(pNode->random != nullptr)
{
pCloned->random = pNode->random->next;
}
pNode = pCloned->next;
}
}
//第三步
RandomListNode* ReconnectNodes(RandomListNode* pHead)
{
RandomListNode* pNode = pHead;
RandomListNode* pClonedHead = nullptr;
RandomListNode* pClonedNode = nullptr;
if(pNode != nullptr)
{
pClonedHead = pClonedNode = pNode->next;
pNode->next = pClonedNode->next;
pNode = pNode->next;
}
while(pNode != nullptr)
{
pClonedNode->next = pNode->next;
pClonedNode = pClonedNode->next;
pNode->next = pClonedNode->next;
pNode = pNode->next;
}
return pClonedHead;
}
};
测试用例:
a.功能测试(节点中的random指向节点自身;两个节点的random形成环状结构;链表中只有一个节点)。
b.特殊输入测试(指向链表头节点的指针为nullptr指针)。