复制带有random指针的单链表

如图1所示,有一条单链表,其节点除了有next指针外,还有一个random指针。random指针可指向单链表中的任意节点,包括它自身。random指针一旦指定,便不再更改。请设计算法,复制此单链表,并给出时间复杂度。

这里写图片描述

图1 带有random指针的单链表

解法1. 时间复杂度为O(n*n)

先按next指针,将链表复制一份。使用p1指向原链表的头节点,p2指向p1指向的节点的random节点,p3指向p1的next节点,cnt记录p3移动的步数,p4指向新链表的头节点。对比p3和p2的指向:如果p2和p3地址不一致,则p3移向本节点的next节点,并记录移动的频数加1。如此反复,直到p3指向的地址与p2指向的地址一致。使用p5指向p4的next节点,再向后移动cnt次,得到p4指向的节点的random指针应该指向的位置。将p1和p4同时移向各自的next。如此反复。

解法2. 时间复杂度为O(2n)

想要降低时间复杂度,就需要增加空间复杂度,拿空间换时间。解法1的时间复杂度高的原因为查找新链表中random指针的指向,哈希表可解决查找慢的问题。

可建立一个hash表,使用原链表的节点的地址的hash值作下标,使用新链表对应的地址作value。这样遍历原链表一遍后,节点的random指向为NULL的新链表可建立起来,并且建立了一张hash表。再遍历一遍,p1指向原链表中某节点,p2指向新链表中对应的某节点。将p1的random指针指向的地址做hash后,可得到hash表中新链表对应的地址值。再将p2的random指针指向该地址即可。如此反复。

解法3. 时间复杂度为O(2n),空间复杂度为O(1)

解法2所花费的空间有些大了,解决法通破坏原链表的方法,代替了hash表,解决了查找random指针指向的问题。虽然原链表被破坏了,但可被恢复到原样。

首先遍历原链表,同时建立新链表。将新链表的random指针指向原链表对应节点的next节点,将原链表的next指针指向新链表的对应节点。

再遍历一次原链表和新链表,p1指向原链表的某节点,p2指向新链表的对应节点。从p1可知random指向的节点,从此节点的next指针可知新链表的对应节点,使用p3指针指向该节点。将p1的next指向p2的random指针指向的节点,再将p2的random指针指向p3。p1和p2均指向自己的next节点。如此反复。

解法3的示意图如下:

这里写图片描述




RandomListNode *copyRandomList(RandomListNode *head) {  
        // write your code here  
        RandomListNode *p = head;  
        RandomListNode *dest, *t = NULL;  
        while (p != NULL) {  
            t = new RandomListNode(p->label);  
            t->next = p->next;  
            t->random = p->random;  
            p->next = t;  
            p = t->next; //取得源链表中的下一个结点  
        }  

        p = head;  
        while (p != NULL) {  
            t = p->next;  
            if (t->random != NULL) {  // 此处需要判断源节点的random是否为空,如果不为空才需要更新  
                t->random = t->random->next;  
            }  
            p = t->next;  
        }  

        p = head;  
        dest = p->next;  
        while (p != NULL) {  
            t = p->next;  
            p->next = t->next; //新旧链表分离的旧(源)链表  
            p = t->next;  
            if (p != NULL) {  
                t->next = p->next;  //新旧链表分离的新链表  
            }  
        }  

        return dest;  
    }  
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值