面试题26:复杂链表的复制

本文介绍了一种高效复制带有额外随机指针的复杂链表的方法。通过三个步骤:复制节点并穿插进原链表、调整随机指针、拆分链表为原链表和复制链表,实现了O(n)时间复杂度且无需额外空间。

       题目:复制一个复杂链表。在复杂链表中,每个节点除了有一个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;
    }
};
       总共分三步来处理,第一步,复制节点,并且把复制节点分别插入到每个待复制节点的后面。第二步,都插另外一个指针。第三步,将链表分离成两个链表。一个之前的,一个是复制的。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值