【剑指offer】链表——025 复杂链表的复制


在这里插入图片描述


题目内容

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

题目分析

这道题目乍一看可能难度不大,但是真正写起来就会发现,当我按照输入链表的顺序,从头到尾复制了一个新的链表,开始从头处理特殊指针的时候,如何找到当前结点的特殊指针,即定义里面的random指向的结点在新复制的链表里的位置。如果用暴力破解方法每次都做一个遍历查找,那么时间很容易就变成了 O ( n 2 ) O(n^2) O(n2)。所以最好能建立一个映射关系,即访问输入链表的某一结点,能在 O ( 1 ) O(1) O(1)的时间上找到复制链表对应的结点。

解题

利用map

C++的map能为两个变量直接建立关系,即map<key, value>。并且能够通过key直接访问value,如map[key] = value;

代码

/*
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 NULL;
        map<RandomListNode*, RandomListNode*> mp;
        RandomListNode* currNode = pHead;
        while(currNode != NULL){
            mp[currNode] = new RandomListNode(currNode->label);
            currNode = currNode->next;
        }
        currNode = pHead;
        while(currNode != NULL){
            if(currNode->next != NULL)
                mp[currNode]->next = mp[currNode->next];
            if(currNode->random != NULL)
                mp[currNode]->random = mp[currNode->random];
            currNode = currNode->next;
        }
        return mp[pHead];
    }
};

另一种解法

这种解法不借助任何STL工具,仅使用数据结构和算法来完成,主要思路分为三步:

  • 第一次遍历输入链表,复制得到结点且将其插入到当前结点的next位置;
  • 第二次遍历上一步得到的链表,当前结点的复制结点的random指针指向的位置为当前的结点的random指针指向位置得复制结点;
  • 第三次遍历上一步得到的链表,拆分为输入链表和输入链表。

如果文字理解不方便,可以看图示,用{A,B,C}表示输入链表的结点,用{A’,B’,C’}表示复制链表的结点。
在这里插入图片描述

代码

/*
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 NULL;
        RandomListNode* currNode = pHead;
        while(currNode != NULL){
            RandomListNode* newNode = new RandomListNode(currNode->label);
            newNode->next = currNode->next;
            currNode->next = newNode;
            currNode = newNode->next;
        }
        currNode = pHead;
        while(currNode != NULL){
            RandomListNode* copyNode = currNode->next;
            if(currNode->random != NULL)
                copyNode->random = currNode->random->next;
            currNode = copyNode->next;
        }
        RandomListNode* newHead = pHead->next;
        currNode = pHead;
        while(currNode != NULL){
            RandomListNode* copyNode = currNode->next;
            currNode->next = copyNode->next;
            currNode = currNode->next;
            if(currNode != NULL)
                copyNode->next = currNode->next;
        }
        return newHead;
    }
};

以上思路为个人想法和网络各位大佬的题解的结合,欢迎讨论与指正。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值