复杂链表的复制的几种解法 — C+++实现

题目描述

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

牛客网题目链接

题目图示

在这里插入图片描述
如图,结点的next的指向下一结点,random指针指向随机结点。

解题思路1:一般法

要实现深复制,应把原来的next指针的和random指针都实现复制。

  • 对于next指针的复制,需要按原来链表的关系逐步复制(新建结点,然后对应好结点的下一个结点(next))
  • 对于random指针的复制,由于其指向是随机的,因此需要从原来的整个链表里进行查找

由于链表中的random指针是随机的,需要遍历一遍列表才能完成复制,在寻找结点时需要从查找,因此这种方法的时间复杂度较高,为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 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)return NULL;
        RandomListNode *reHead;
        reHead=copy_next(pHead);
        return copy_rand(pHead,reHead);
	}
	RandomListNode* copy_next(RandomListNode* pHead){
	    RandomListNode *head=NULL,*tmp,*ptr,*last;
	    tmp=pHead;
	    while(tmp){
	        ptr=new RandomListNode(tmp->label);
	        if(head) last->next=ptr;
	        else head=ptr;
            last=ptr;
            tmp=tmp->next;
	    }
	    return head;
	}
    RandomListNode *copy_rand(RandomListNode *pHead,RandomListNode *reHead){
        RandomListNode *tmp=pHead,*ratmp,*retmp=reHead;
        int index,i;
        while(tmp){
            if(tmp->random){
                index=look(pHead,tmp->random);
                ratmp=reHead;
                for(i=0;i<index;i++)ratmp=ratmp->next;
                retmp->random=ratmp;
            }
            retmp=retmp->next;
            tmp=tmp->next;
        }
        return reHead;
    }
    int look(RandomListNode *pHead,RandomListNode *tar){
        RandomListNode *tmp=pHead;
        int i;
        for(i=0;tmp;i++){
            if(tmp==tar)return i;
            tmp=tmp->next;
        }
    }
};
运行时间:2ms

占用内存:504k

解题思路2:哈希法

我们可以先将原链表的next完整地进行复制,同时将原链表和复制链表的对应关系存在哈希表里。

然后再复制random指针,只需要在哈希表里查找到对应的结点并连接就完成了复制。

这是一种以空间换取空间的方法,时间复杂度为 O ( n ) O(n) O(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)return NULL;
        return hash_copy(pHead);
    }
    RandomListNode* hash_copy(RandomListNode* pHead){
        RandomListNode *head=NULL,*tmp,*ptr,*last,*pc;
        tmp=pHead;
        map <RandomListNode *,RandomListNode *> tab;
        while(tmp){
            ptr=new RandomListNode(tmp->label);
            tab[tmp]=ptr;
            if(head) last->next=ptr;
            else head=ptr;
            last=ptr;
            tmp=tmp->next;
        }
        tmp=pHead,pc=head;
        while(tmp){
            if(tmp->random)pc->random=tab[tmp->random];
            tmp=tmp->next;
            pc=pc->next;
        }
        return head;
    }
};
运行时间:2ms

占用内存:388k

解题思路3:推荐解法

可以在原链表的结点后面插入一个值相同的结点,这样我们在复制random所指结点的时候只需要让该结点的下一结点指向random指向结点的下一结点即可。

以上操作完成后的链表结构如下图所示,我们要提取结果的话只需要将偶数位置上的结点提取出来即可。
在这里插入图片描述
NOTE:不能改变原链表结构

由于我们已经改变了原链表的结构,因此需要恢复原链表。

代码实现

/*
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)return NULL;
        RandomListNode *res;
        res=copy_next(pHead);
        res=copy_random(res);
        res=result(res);
        return res;
    }
    RandomListNode *copy_next(RandomListNode* pHead){
        RandomListNode *tmp=pHead,*pn,*ptr;
        while(tmp){
            pn=tmp->next;
            ptr=new RandomListNode(tmp->label);
            tmp->next=ptr;
            ptr->next=pn;
            tmp=pn;
        }
        return pHead;
    }
    RandomListNode *copy_random(RandomListNode* pHead){
        RandomListNode *tmp,*pn;
        tmp=pHead;
        while(tmp){
            if(tmp->random)tmp->next->random=tmp->random->next;
            tmp=tmp->next->next;
        }
        return pHead;
    }
    RandomListNode *result(RandomListNode* pHead){
        RandomListNode *tmp,*node,*last,*reHead;
        tmp=pHead,node=pHead;
        last=tmp->next,reHead=last,tmp=last->next;
        node->next=tmp;
        while(tmp){
            node=tmp;
            last->next=tmp->next;
            last=tmp->next;
            tmp=last->next;
            node->next=tmp;
        }
        return reHead;
    }
};
运行时间:2ms

占用内存:504k
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值