复杂链表的复制
一、题目
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
二、解析
需要注意的是每个节点都有两个指针
其实这题如果可以用深拷贝直接就出来了哈哈哈!
import copy
class Solution:
# 返回 Ran00domListNode
def Clone(self, pHead):
# write code here
ret = copy.deepcopy(pHead)
return ret
比如:如下就是一个复杂链表。正常情况下,你把node1,node2复制过去,但是你不知道random在哪里,你每次搜寻random,你都要搜寻n次,复杂度n^2。太慢,我们尽量不要做n平方的事情
大神想的招:每个节点都复制一份,如下:然后根据原本链表连接random,那么新复制的节点的random为None,现在我们要做的是将新的节点找到random,然后把老的节点删除就好了。
如何指定新的节点的指针?很简单,新的节点的random指针指向的位置就是老节点random的next,就是原本random指向的节点的下一位。
a.next.random(a.next就是新复制的节点) = a.random.next
然后断链,将原本的链拿走,这样的时间复杂度为3n:循环第一次,复制节点,循环第二次,找random;循环第三次,断开链表
- 边界条件(永远不要忘了):如果pHead不存在,返回None
- 开启第一次循环:复制node——(1)首先我们要有一个指针pTmp = pHead,开始循环,循环的终止条件是pTmp为空。循环体内,首先要建立一个node,这个node等于谁?等于复杂链表的类RandomListNode,就是先实例化,类里面的参数x是原本的复杂链表的节点的label,即每一个
node = RandomListNode(pTmp.label)
,现在知道这个指针pTmp有啥用了吧,就是在每一次循环的时候这个指针沿着原链表变动,为我们提供复杂链表类中的参数从而生成新的node,你可以把这个指针看作是原本链表的指针;(2)你现在创建完了,需要将它正常的连接起来,首先原本节点的next指向node,node的next指向原本节点的next,但是是否有不妥,这样不对,顺序不对,反过来,否则的话原本节点的next为node了。你再让node指向自己?·node.next = pTmp.next, pTmp.next = node·, 然后更新指针:pTmp = node.next
,结束循环! - 开启第二次循环:找到node的random——(1)你要记得只要遍历链表,你就必要要创建一个指针,由于上个循环已经结束,所以名字可以一样,因此创建指针
pTmp = pHead
;考虑全面一点,因为random是有可能为空的,在创建链表类的时候,链表最后一个的next为空,对应的,类内部x.random=None,所以random有可能为空:if pTmp.random,只有满足了这个条件才能继续执行:node.random = pTmp.random.next
;更新指针:pTmp = node.next
- 开启第三次循环:断开原本链表与新链表之间的联系:在断开之前,你要做一件事:你这个函数要返回什么,返回的是新链表的newhead,这个newhead如何得到?新建指针pTmp = pHead, newhead = pTmp.next;然后进入循环,如何断链,原本的pTmp.next为node,现在我不要你指向我了,你还是指向你原本应该指向的东西pTmp.next,next吧;还不够,你不光要断掉原本的节点与新node的联系,你还要断掉新node与原本节点的联系,所以在进入循环之前还要创建一个新链表的指针pNewTmp,pNewTmp现在指向的是node.next,现在可不敢了,他应该指向node.next,next,所以
if pNewNext:
,pNewTmp.next = pNewTmp.next,next
,最后更新pTmp
# -*- coding:utf-8 -*-
# class RandomListNode:
# def __init__(self, x):
# self.label = x
# self.next = None
# self.random = None
class Solution:
# 返回 Ran00domListNode
def Clone(self, pHead):
# write code here
# 第一次循环需要加所有的node
# 复制一样的node并且添加到之前的链表的每一个node后面
if pHead == None:
return None
pTmp = pHead
while pTmp:
node = RandomListNode(pTmp.label)
# 复制的这个节点的next等于原本节点的next
node.next = pTmp.next # pTmp.next可以为none,是None的话node.next就是None,但是第二个循环的random不行,如果random为none;random.next怎么办
# 原本节点的next换成指向新复制的节点
pTmp.next = node
# 更新pTmp
pTmp = node.next
# 实现新建的node的random的指向
pTmp = pHead
while pTmp:
if pTmp.random:
pTmp.next.random = pTmp.random.next
# 更新pTmp
pTmp = pTmp.next.next
# 断链:断开原来node与新的node之间的连接
pTmp = pHead
newHead = pHead.next
pNewTmp = pHead.next
while pTmp:
pTmp.next = pTmp.next.next
if pNewTmp.next:
pNewTmp.next = pNewTmp.next.next
pNewTmp = pNewTmp.next
pTmp = pTmp.next
return newHead