LeetCode(138) Copy List with Random Pointer

题目

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.

分析

实现一个链表的深拷贝,返回拷贝后的新链表。

若是普通链表,逐个拷贝原始链表节点并连接即可,只需O(n)的时间复杂度;但是此题特殊的是,每个节点都有一个random域可以指向该链表中的任何一个节点,所以直接复制无法处理random域,因为其指向的节点很有可能还没有创建出来。

有两种方法处理:
方法一:暴力解决,首先不处理random域,将原始链表复制一份,然后遍历每个原始链表节点,查找其random域,将新链表的对应节点链接,该方法需要O(n^2)的时间复杂度,给出的结果是TLE。

方法二:充分利用原始链表的信息,不用保存原始链表的映射关系,构建新节点时,指针做如下变化,即把新节点插入到相应的旧节点后面(参考):

例子
同理分两步

1、构建新节点random指针:

new1->random = old1->random->next, new2-random = NULL, 
new3-random = NULL, new4->random = old4->random->next

2、恢复原始链表以及构建新链表:

old1->next = old1->next->next,  new1->next = new1->next->next

该算法时间复杂度O(N),空间复杂度O(1)

AC代码

class Solution {
public:
    //方法一:直接复制,再修改random指针
    RandomListNode *copyRandomList1(RandomListNode *head) {
        if (!head)
            return NULL;

        RandomListNode *ret = new RandomListNode(head->label), *q = ret;
        RandomListNode *p = head->next;
        while (p)
        {
            RandomListNode *tmp = new RandomListNode(p->label);
            q->next = tmp;
            q = q->next;

            p = p->next;
        }//while
        q->next = NULL;

        //处理原始链表的random指针
        p = head, q = ret;
        RandomListNode *idx1 = head, *idx2 = ret;
        while (p)
        {
            if (p->random == NULL)
                q->random = NULL;
            else{
                idx1 = head;
                idx2 = ret;
                while (p->random->label != idx1->label)
                {
                    idx1 = idx1->next;
                    idx2 = idx2->next;
                }//while
                q->random = idx2;
            }//else
            p = p->next;
            q = q->next;
        }//while
        return ret;
    }

    //方法二:充分利用原始链表信息,在每个节点后复制添加
    RandomListNode *copyRandomList(RandomListNode *head) {
        if (!head)
            return NULL;

        //首先,复制原始的节点,连接自身后面
        RandomListNode *p = head;
        while (p)
        {
            RandomListNode *tmp = new RandomListNode(p->label);
            //保存后续节点
            RandomListNode *r = p->next;

            tmp->next = r;
            p->next = tmp;

            p = r;
        }//while

        //然后,将添加的节点random 链接到原始节点random的下一个位置
        p = head;
        while (p)
        {
            RandomListNode *q = p->next;
            if (p->random == NULL)
                q->random = NULL;
            else{
                q->random = p->random->next;
            }//else
            //处理下一个原始节点
            p = q->next;
        }//while

        //最后,恢复原始链表,得到新链表
        RandomListNode *ret = head->next;

        p = head;
        RandomListNode *q = head->next;
        while (q->next)
        {
            p->next = q->next;
            p = q;
            if (q->next)
                q = q->next;
        }
        p->next = NULL;
        q->next = NULL;
        return ret;
    }

};

GitHub测试程序源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值