[编程题]复杂链表的复制
时间限制:1秒 空间限制:32768K
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
解法一:递归法
递归思想:把大问题转化若干子问题
此题转化为一个头结点和除去头结点剩余部分,剩余部分操作和原问题一致
Python解法
# -*- coding:utf-8 -*-
# class RandomListNode:
# def __init__(self, x):
# self.label = x
# self.next = None
# self.random = None
class Solution:
# 返回 RandomListNode
def Clone(self, headNode):
# write code here
if headNode is None: return
theNewNode = RandomListNode(headNode.label)
theNewNode.random = headNode.random
theNewNode.next = self.Clone(headNode.next)
return theNewNode
C++解法
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead == NULL)
return NULL;
unordered_map<RandomListNode*, RandomListNode*> M;
for(RandomListNode *p=pHead;p!=NULL;p=p->next)
M[p] = new RandomListNode(p->label);
for(RandomListNode *p=pHead;p!=NULL;p=p->next)
{
M[p]->next = M[p->next];
M[p]->random = M[p->random];
}
return M[pHead];
}
};
解法二:哈希表法,借助map空间换时间
利用空间节省时间,时间复杂度O(n)。
map关联
1.首先遍历一遍原链表,创建新链表(赋值label和next),用map关联对应结点(存储原节点指向对应新节点的指针);再遍历一遍,更新新链表的random指针。(注意map中应有NULL —-> NULL的映射)
2.不能改变原有链表
C++解法
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;
}
};
- 看到网上有人用multimap,思路基本相同遍历两边链表,第一遍用multimap映射对应关系到hashtable(存储原节点指向对应新节点的指针)不设置random指针,第二遍更新新链表的random指针.两个都能运行通过
“`cpp
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead==NULL)return NULL;
//创建新链表的头结点
RandomListNode *pCloneHead=new RandomListNode(pHead->label);
pCloneHead->next=NULL;
pCloneHead->random=NULL;
//设置一个哈希map存储映射关系
//由于不同结点的random可能指向同一个结点,所以用multimap而不是map
unordered_multimap
2.也有人使用STL中的map来映射原来的地址和复制后的地址, 递归代码很精简
```cpp
class Solution {
public:
map< RandomListNode *, RandomListNode *> point_map;
RandomListNode* Clone(RandomListNode* pHead){
if(pHead == NULL) return NULL;
RandomListNode* now = new RandomListNode(pHead->label);
point_map[pHead] = now;//映射原来地址 到新地址
now->next = Clone(pHead->next);
now->random = point_map[pHead->random];
return now;
}
};
<div class="se-preview-section-delimiter"></div>
Python解法
class Solution:
def Clone(self, head):
nodeList = [] #存放各个节点
randomList = [] #存放各个节点指向的random节点。没有则为None
labelList = [] #存放各个节点的值
while head:
randomList.append(head.random)
nodeList.append(head)
labelList.append(head.label)
head = head.next
#random节点的索引,如果没有则为1
labelIndexList = map(lambda c: nodeList.index(c) if c else -1, randomList)
dummy = RandomListNode(0)
pre = dummy
#节点列表,只要把这些节点的random设置好,顺序串起来就ok了。
nodeList=map(lambda c:RandomListNode(c),labelList)
#把每个节点的random绑定好,根据对应的index来绑定
for i in range(len(nodeList)):
if labelIndexList[i]!=-1:
nodeList[i].random=nodeList[labelIndexList[i]]
for i in nodeList:
pre.next=i
pre=pre.next
return dummy.next
<div class="se-preview-section-delimiter"></div>
解法三:直接使用Python Copy包中的深度拷贝
import copy
class Solution:
def Clone(self, pHead):
chead=copy.deepcopy(pHead)
return chead
直接赋值:其实就是对象的引用(别名)。
浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。
深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。
参考:
文档-copy — Shallow and deep copy operations
关于deepcopy这个博客也解释的很详细