35 复杂链表的复制( 分解让复杂问题简单)
题目描述:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
测试用例:
功能测试(节点中的random指向自身;两个节点的random形成环状结构;链表中只有一个节点)
特殊输入测试(空链表nullptr)
解题思路:
1)分成三步:
一、根据原始链表创建每个节点N对应的N’。把每个N' 连接到N的后面。(插入到原结点后方)
二、赋值节点的random指针
三、拆分两个链表
class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { CloneNodes(pHead); ConnectRandomNodes(pHead); return ReConnectNodes(pHead); } //第一步 在原链表每个节点的后面复制链表 void CloneNodes(RandomListNode* pHead){ RandomListNode* pNode= pHead; while(pNode){ RandomListNode* pClone = new RandomListNode(pNode->label); //构造函数要传值 pClone->next = pNode->next; pClone->random = nullptr; pNode->next = pClone; pNode = pClone->next; } } //第二步 对random赋值 void ConnectRandomNodes(RandomListNode* pHead){ RandomListNode* pNode= pHead; while(pNode){ RandomListNode* pClone = pNode->next; if(pNode->random) pClone->random = pNode->random->next; pNode = pClone->next; } } //第三步 拆分链表 RandomListNode* ReConnectNodes(RandomListNode* pHead){ RandomListNode* pNode= pHead; RandomListNode* pCloneHead= nullptr; RandomListNode* pCloneNode= nullptr; if(pNode){//处理头节点 pCloneHead=pCloneNode=pNode->next; pNode->next = pCloneNode->next; pNode = pNode->next; } while(pNode){ pCloneNode->next = pNode->next; //连接复制的链表 pCloneNode = pNode->next; pNode->next = pCloneNode->next; //连接原来的链表 pNode = pNode->next; } return pCloneHead; } };
2)哈希表方法
分为两步:
一、复制原始列表的val与next,random置空,并使用哈希表存储<N,N'>的配对信息。
二、设置复制链表上的每个random指针。
class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { if(pHead==NULL) return NULL; //定义一个哈希表 unordered_multimap<RandomListNode*,RandomListNode*> table; // 开辟一个头结点 RandomListNode* pClonedHead=new RandomListNode(pHead->label); pClonedHead->next=NULL; pClonedHead->random=NULL; // 将头结点放入map中 table.insert(make_pair(pHead,pClonedHead)); //设置操作指针 RandomListNode* pNode=pHead->next; RandomListNode* pClonedNode=pClonedHead; // 第一遍先将简单链表复制一下 while(pNode!=NULL) { // 不断开辟pNode的拷贝结点 RandomListNode* pClonedTail=new RandomListNode(pNode->label); pClonedTail->next=NULL; pClonedTail->random=NULL; //连接新节点,更新当前节点 pClonedNode->next=pClonedTail; pClonedNode=pClonedTail; //将对应关系 插入到哈希表中 table.insert(make_pair(pNode,pClonedTail)); //向后移动操作节点 pNode=pNode->next; } //需从头开始设置random节点,设置操作指针 pNode=pHead; pClonedNode=pClonedHead; // 根据map中保存的数据,找到对应的节点 while(pNode!=NULL) { if(pNode->random!=NULL) { //找到对应节点,更新复制链表 pClonedNode->random=table.find(pNode->random)->second; } //向后移动操作节点 pNode=pNode->next; pClonedNode=pClonedNode->next; } return pClonedHead; } };
3)使用map存储<N,N'>的配对信息
class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { if(pHead==NULL) return NULL; map<RandomListNode*,RandomListNode*> m; RandomListNode* pHead1 = pHead; RandomListNode* pHead2 = new RandomListNode(pHead1->label); RandomListNode* newHead = pHead2; m[pHead1] = pHead2; while(pHead1){ if(pHead1->next) pHead2->next = new RandomListNode(pHead1->next->label); else pHead2->next = NULL; pHead1 = pHead1->next; pHead2 = pHead2->next; m[pHead1] = pHead2; } pHead1 = pHead; pHead2 = newHead; while(pHead1){ pHead2->random = m[pHead1->random]; pHead1 = pHead1->next; pHead2 = pHead2->next; } return newHead; } };