题目如下:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
本题在《剑指offer》里面提供了除了直接复制两种指针之外的两种思路,下面分别讨论。
第一种:使用一个哈希表存储节点信息,是一种用空间换时间的方法,时间复杂度为O(n)。
首先在新的链表里开始复制节点的Next信息,在复制Next信息的时候,建立一个哈希表,哈希表的键为旧链表里面的节点,值为新链表里面的节点,如:将旧链表的节点node赋值给新链表的node_1后,给哈希表添加一个键值对:nodeMap[node] = node_1。
这样做的好处是在第一次复制完Next信息之后,哈希表也建立好了,在复制random节点时,由于有哈希表的键值对,因此,找到node_1的random的时间复杂度为O(1),即:node_1->random = nodeMap[node->random]。
具体代码如下:
class Solution {
private:
RandomListNode * result;
map<RandomListNode*, RandomListNode*> nodeMap;
public:
RandomListNode * cloneNext(RandomListNode* pHead) {
RandomListNode *temp, *pHeadNew = pHead, *tempNew, *resultTemp;
temp = new RandomListNode(0);
resultTemp = temp;
while (pHeadNew != NULL) {
tempNew = new RandomListNode(0);
tempNew->label = pHeadNew->label;
temp->next = tempNew;
temp = temp->next;
nodeMap[pHeadNew] = tempNew;
pHeadNew = pHeadNew->next;
}
temp = resultTemp->next;
while (pHead != NULL) {
if (pHead->random != nullptr) {
temp->random = nodeMap[pHead->random];
}
else temp->random == nullptr;
pHead = pHead->next;
temp = temp->next;
}
return resultTemp->next;
}
RandomListNode * Clone(RandomListNode* pHead)
{
if (pHead == NULL) return result;
else {
return cloneNext(pHead);
}
}
};
书中介绍的第二种方法:主要分为三步:首先:将链表中的节点都复制一份,并把相应的复制之后的节点连接在原来节点后面,第二步:复制random指针,由于之前的复制,那么假如A点的random指针指向C点,那么A后面的A’点的random指针必然指向C点后面的C’点,第三步:将这个链表中的点分开,偶数节点连接成一个新的链表,这个链表就是我们需要的链表。
具体代码如下:
class Solution {
private:
RandomListNode * result;
map<RandomListNode*, RandomListNode*> nodeMap;
public:
RandomListNode * cloneNode(RandomListNode* pHead) {
RandomListNode* pHeadNew = pHead;
while (pHead != nullptr) {
RandomListNode* temp = new RandomListNode(0);
temp->label = pHead->label;
RandomListNode* nextNode = pHead->next;
pHead->next = temp;
temp->next = nextNode;
pHead =temp->next;
}
pHead = pHeadNew;
while (pHead != nullptr) {
RandomListNode*temp = pHead->random;
if (temp != nullptr)
pHead->next->random = temp->next;
else
pHead->next == nullptr;
pHead = pHead->next->next;
}
return pHeadNew;
}
RandomListNode* ReconnentNode(RandomListNode* pHead) {
RandomListNode* pNode = pHead;
RandomListNode* pClonedHead = new RandomListNode(0);
RandomListNode* pClonedNode = pClonedHead;
do {
pClonedNode->next = pNode->next;
pClonedNode = pClonedNode->next;
pNode->next = pClonedNode->next;
pNode = pNode->next;
} while (pNode!=nullptr);
return pClonedHead->next;
}
RandomListNode * Clone(RandomListNode* pHead)
{
cout << endl;
if (pHead == nullptr) return result;
RandomListNode*head = cloneNode(pHead);
return ReconnentNode(head);
}
};
对于ReconnentNode函数,我画了个图在下面,看起来会清楚点
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/391a08bc7c7b4b3c96df9a3313f1a998.jpeg)