剑指offer(python)-题目26-复杂链表的复制********

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

1.如果链表为空链表,则返回本身即可
2.如果非空 需要进行复制操作,如果没有特殊指针,只需要复制next我相信大家都能很快做出来,但是加上特殊指针这就需要一定技巧,因为特殊指针随便指,而你每次找特殊指针所指的节点都需要从头开始遍历找起,这显然复杂度高达O(n²)

方法1:

在不使用辅助空间的情况下实现O(N)的时间效率。

  1. 把复制的结点链接在原始链表的每一对应结点后面

  2. 把复制的结点的random指针指向被复制结点的random指针的下一个结点

  3. 拆分成两个链表,奇数位置为原链表,偶数位置为复制链表,注意复制链表的最后一个结点的next指针不能跟原链表指向同一个空结点None,next指针要重新赋值None(判定程序会认定你没有完成复制)

原文:https://blog.csdn.net/jiangjiang_jian/article/details/81490693
https://blog.csdn.net/qq_33431368/article/details/79296360

如图
首先第一步 复制原来的链表,顺次连接形成新链表

在这里插入图片描述

 cloNode = pHead
        while cloNode:
            #完成第一步的核心操作
            node = RandomListNode(cloNode.label)
            node.next = cloNode.next
            cloNode.next = node
              cloNode = node.next #下一次操作

第二步,利用原节点的random指向,来用复制的相应节点的random

  cloNode = pHead
        while cloNode:
            node = cloNode.next #指向复制的结点
            if cloNode.random: #如果原节点有特殊指针
                node.random = cloNode.random.next #则复制的节点的特殊指针指向原节点的特殊指针指向的下一个值  看图更好理解一些
            cloNode = node.next

最后一步,将复制好的链表拆分出来,或者说将 偶数位的节点重新拆分合成新的链表,得到的就是复制的链表

在这里插入图片描述

 cloNode = pHead
        pHead = pHead.next
        while cloNode.next:
            #完成第三步的核心操作 此时节点指向隔了一个节点的节点
            node = cloNode.next
            cloNode.next = node.next
            
            cloNode = node #下一个节点的操作

这个操作其实就是将两个链表顺次全都拆分出来,一个很关键的步骤 pHead = pHead.next 如果没有这句话,最后得到的pHead就是原链表的开头了。

总程序如下:

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # write code here
        if not pHead:
            return pHead
        cloNode = pHead
        while cloNode:
            node = RandomListNode(cloNode.label)
            node.next = cloNode.next
            cloNode.next = node
            cloNode = node.next
        cloNode = pHead
        while cloNode:
            node = cloNode.next
            if cloNode.random:
                node.random = cloNode.random.next
            cloNode = node.next
        cloNode = pHead
        pHead = pHead.next
        while cloNode.next:
            node = cloNode.next
            cloNode.next = node.next
            cloNode = node
        return pHead

方法2:递归

class Solution:
    def Clone(self, head):
        if not head: return
        newNode = RandomListNode(head.label)
        newNode.random = head.random
        newNode.next = self.Clone(head.next)
        return newNode

方法3:

实际上我们可以通过空间换取时间,将原始链表和复制链表的结点通过哈希表对应起来,这样查找的时间就从O(N)变为O(1)。具体如下:

复制原始链表上的每个结点N创建N’,然后把这些创建出来的结点用pNext连接起来。同时把<N,N’>的配对信息方法一个哈希表中;然后设置复制链表中的每个结点的pSibling指针,如果原始链表中结点N的pSibling指向结点S,那么在复制链表中,对应的N’应该指向S’。

时间复杂度:O(N)

class Solution:
    def Clone(self, head):
        nodeList = []     #存放各个节点
        randomList = []   #存放各个节点指向的random节点。没有则为None
        labelList = []    #存放各个节点的值
 
        while head:
            randomList.append(head.random)
            nodeList.append(head)
            labelList.append(head.label)
            head = head.next
        #random节点的索引,如果没有则为1   
        labelIndexList = map(lambda c: nodeList.index(c) if c else -1, randomList)
 
        dummy = RandomListNode(0)
        pre = dummy
        #节点列表,只要把这些节点的random设置好,顺序串起来就ok了。
        nodeList=map(lambda c:RandomListNode(c),labelList)
        #把每个节点的random绑定好,根据对应的index来绑定
        for i in range(len(nodeList)):
            if labelIndexList[i]!=-1:
                nodeList[i].random=nodeList[labelIndexList[i]]
        for i in nodeList:
            pre.next=i
            pre=pre.next
        return dummy.next

猜你喜欢

转载自blog.csdn.net/qq_24429333/article/details/87882684
今日推荐