面试题26:复杂链表的复制
2016-07-03 20:20
375 查看
题目:复制一个复杂链表。在复杂链表中,每个节点除了有一个next指针指向下一个节点外,还有一个指针指向链表中的任意节点或者NULL。
这道题之前从未见过。一开始反应是先按照正常的链表复制方法。也就是只有next指针的链表。然后再重新遍历一遍,复制链表的另外一个指针。但是,要考虑寻找一个已知的链表节点的时间复杂度是O(n),必须从头往后遍历。也就使得整个算法的时间复杂度是O(n*n).这显然复杂度太高了。
看了下书上的解释,想着维护一个map,记录每个节点的另外一个指针,待复制后,直接取出指向它即可。这相当于用空间复杂度去换取时间复杂度。用O(n)的空间复杂度使得算法的时间复杂度由O(n*n)编程O(n),一般来说这就是比较理想的了,毕竟现在内存这么便宜。然而书上还有另外一个方法,不需要O(n)空间复杂度,也可以o(n)时间,简直逆天了,方法如下:
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead==NULL)
return pHead;
RandomListNode *tempNode=pHead;
cloneNode(tempNode);
connectRandom(tempNode);
return pickDump(tempNode);
}
void cloneNode(RandomListNode* headNode)
{
RandomListNode *pHead=headNode;
while(pHead)
{
RandomListNode *newNode=new RandomListNode(0);
newNode->label=pHead->label;
newNode->next=pHead->next;
newNode->random=NULL;
pHead->next=newNode;
pHead=newNode->next;
}
}
void connectRandom(RandomListNode* headNode)
{
RandomListNode *pHead=headNode;
while(pHead)
{
if(pHead->random!=NULL)
{
pHead->next->random=pHead->random;
}
pHead=pHead->next->next;
}
}
RandomListNode* pickDump(RandomListNode* pHead)
{
RandomListNode *newHead;
RandomListNode *oldNode=pHead;
if(oldNode)
{
newHead=oldNode->next;
oldNode->next=newHead->next;
oldNode=oldNode->next;
}
RandomListNode *curNode=newHead;
while(oldNode)
{
curNode->next=oldNode->next;
curNode=curNode->next;
oldNode->next=curNode->next;
oldNode=oldNode->next;
}
return newHead;
}
}; 总共分三步来处理,第一步,复制节点,并且把复制节点分别插入到每个待复制节点的后面。第二步,都插另外一个指针。第三步,将链表分离成两个链表。一个之前的,一个是复制的。
这道题之前从未见过。一开始反应是先按照正常的链表复制方法。也就是只有next指针的链表。然后再重新遍历一遍,复制链表的另外一个指针。但是,要考虑寻找一个已知的链表节点的时间复杂度是O(n),必须从头往后遍历。也就使得整个算法的时间复杂度是O(n*n).这显然复杂度太高了。
看了下书上的解释,想着维护一个map,记录每个节点的另外一个指针,待复制后,直接取出指向它即可。这相当于用空间复杂度去换取时间复杂度。用O(n)的空间复杂度使得算法的时间复杂度由O(n*n)编程O(n),一般来说这就是比较理想的了,毕竟现在内存这么便宜。然而书上还有另外一个方法,不需要O(n)空间复杂度,也可以o(n)时间,简直逆天了,方法如下:
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead==NULL)
return pHead;
RandomListNode *tempNode=pHead;
cloneNode(tempNode);
connectRandom(tempNode);
return pickDump(tempNode);
}
void cloneNode(RandomListNode* headNode)
{
RandomListNode *pHead=headNode;
while(pHead)
{
RandomListNode *newNode=new RandomListNode(0);
newNode->label=pHead->label;
newNode->next=pHead->next;
newNode->random=NULL;
pHead->next=newNode;
pHead=newNode->next;
}
}
void connectRandom(RandomListNode* headNode)
{
RandomListNode *pHead=headNode;
while(pHead)
{
if(pHead->random!=NULL)
{
pHead->next->random=pHead->random;
}
pHead=pHead->next->next;
}
}
RandomListNode* pickDump(RandomListNode* pHead)
{
RandomListNode *newHead;
RandomListNode *oldNode=pHead;
if(oldNode)
{
newHead=oldNode->next;
oldNode->next=newHead->next;
oldNode=oldNode->next;
}
RandomListNode *curNode=newHead;
while(oldNode)
{
curNode->next=oldNode->next;
curNode=curNode->next;
oldNode->next=curNode->next;
oldNode=oldNode->next;
}
return newHead;
}
}; 总共分三步来处理,第一步,复制节点,并且把复制节点分别插入到每个待复制节点的后面。第二步,都插另外一个指针。第三步,将链表分离成两个链表。一个之前的,一个是复制的。
相关文章推荐
- 推荐!国外程序员整理的Java资源大全
- 高级Java面试题汇总
- Android面试题(一)——Activity的生命周期和启动模式
- android开发面试问题总结
- 高效程序员的45个习惯第二章
- 【66】Scanner类用法详解
- 华为机试题【1】
- 面试题25:二叉树中和为某一值的路径
- 前端工程师面试题汇总
- 是程序员都可以做的政企。。。
- 超全!iOS 面试题汇总
- 百度面试题
- 面试
- 面试题
- 常见面试之机器学习算法思想简单梳理
- 剑指offer-3-面试13:在O(1)时间删除链表结点
- 136课: Spark面试经典系列之数据倾斜解决原理和方法总论.
- 前端工程师面试题汇总
- 一篇非常不错的前端面试文章
- IT软件开发常用英语词汇