数据结构与算法-链表(六):剑指offer-复杂链表的复制

复杂链表的复制

一、题目

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的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
发布了49 篇原创文章 · 获赞 2 · 访问量 1821

猜你喜欢

转载自blog.csdn.net/liuluTL/article/details/104981979
今日推荐