剑指Offer - 复杂链表的复制 (C++)

题目描述

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

 

思路1:O(n^2)的复杂度  -- 先按next指针创建出新的链表,然后两层循环实现random指针的指向,外层循环是遍历原数组,内层循环是找到外层循环当前节点的random指针所指向的节点。

 

思路2:O(n)的复杂度

以下面的复杂链表为例:

è¿éåå¾çæè¿°

第一步:仍然是根据原始链表的每个结点N 创建对应的N’。把N’链接在N的后面。图4.8 的链表经过这一步之后的结构,如图4.9 所示。

è¿éåå¾çæè¿°

第二步:设置复制出来的结点的random假设原始链表上的N的sibling指向结点S,那么其对应复制出来的N’是N的pext指向的结点,同样S’也是S的next指向的结点。设置random之后的链表如图4.10 所示。

è¿éåå¾çæè¿°

第三步:把这个长链表拆分成两个链表把奇数位置的结点用next . 
链接起来就是原始链表,把偶数位置的结点用next 链接起来就是复制 
出来的链表。图4. 10 中的链表拆分之后的两个链表如图4.11 所示。

è¿éåå¾çæè¿°

 

思路1代码:

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        RandomListNode *h, *p, *copy_p;
        if(!pHead) return NULL;
        h = copy_p = new RandomListNode(pHead->label);  //创建头结点
        p = pHead->next;
        while(p)  // 第一次遍历原链表(从原链接头结点后面的那个节点开始遍历)
        {
            copy_p->next = new RandomListNode(p->label);
            copy_p = copy_p->next;
            p = p->next;
        }
        
        p = pHead;
        copy_p = h;
        while(p)  // 第一次遍历原链表(从原链接头结点开始遍历)
        {
            int cnt = 0;
            RandomListNode* mid = pHead;
            while(mid)
            {
                if(mid==p->random)
                    break;
                mid = mid->next;
                ++cnt;
            }
            copy_p->random = findRandom(h, cnt);  // 调用函数
            p = p->next;
            copy_p = copy_p->next;
        }
        return h;
    }
    
    RandomListNode* findRandom(RandomListNode* h, int cnt)
    {
        RandomListNode* p = h;
        for(int i=0; i<cnt; ++i)
            p = p->next;
        return p;
    }
};

思路2代码:

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        RandomListNode *h, *p, *copy_p;
        if(!pHead) return NULL;
        p = pHead->next;
        h = new RandomListNode(pHead->label);  // 新建h节点,并符在pHead节点之后
        h->next = pHead->next;
        pHead->next = h;
        //第一次遍历 -- 挂载
        while(p)
        {
            copy_p = new RandomListNode(p->label);  //新建节点并符在p指针指向的节点后面
            copy_p->next = p->next;
            p->next = copy_p;
            
            p = p->next->next;  // p指针后移两步
        }
        // 第二次遍历 实现random指针的指向
        p = pHead;
        copy_p = h;
        while(p)
        {
            if(p->random)  //注意random可能是空指针,这里不要忘了判断一下 --------------- 切记
                copy_p->random = p->random->next;  //copy_p指针的random指向赋值
            
            p = p->next->next;
            if(copy_p->next)  // 否则说明copy_p指向最后一个节点 ----------------------- 切记
                copy_p = copy_p->next->next; // 不要忘了copy_p指针也后移 ------------- 切记
        }
        // 第三次遍历 -- 断链
        p = pHead;
        copy_p = h;
        while(p) // 这里这里是判断p 因为下面第三行p指针会后移。
        {
            p->next = p->next->next;
            p = p->next;
            
            if(copy_p->next)  // -------------------------------------------------- 切记
            {
                copy_p->next = copy_p->next->next;
                copy_p = copy_p->next;
            }
        }
        
        return h;
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值