[剑指Offer] 35_复杂链表的复制

版权声明:Tian Run https://blog.csdn.net/u013908099/article/details/86491966

题目

请实现啊函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个
复杂链表。在复杂链表中除了有一个m_pNext指针指向下一个节点,还有一个m_pSaibling
指针指向链表中的任意节点或者nullptr。

节点定义如下:

class ComplexListNode(object):

    def __init__(self, x):
        self.val = x
        self.next = None
        self.sibling = None

思路

  1. 第一步,复制主链,解决所有节点的next配置。
    第二步,解决silbing配置,遍历旧链表,如果有sibling,则旧链表头遍历寻找该节点,记录离链表头的距离后在新链表里同样设置。
    1. 时间复杂度:O(n^2)
    2. 空间复杂度:O(1)
  2. 第一步,复制主链,解决next,同时设置hash表,将旧节点和新节点建立映射。
    第二步,解决sibling,node遍历旧链表,当有node.sibling时,新链表new_node.sibling设置为hash表中node.sibling映射的结果。
    1. 时间复杂度:O(n)
    2. 空间复杂度:O(n)
  3. 第一步,将主链每个节点都复制一个拷贝连接入原节点的后面。A-B -> A-A’-B-B’
    第二步,将按原节点设置复制节点的sibling,有node’.sibling = node.sibling.next
    第三步,将链表分解成新旧两条,奇数链和偶数链。
    1. 时间复杂度:O(n)
    2. 2空间复杂度:O(1)

代码

思路2:时间复杂度:O(n),空间复杂度:O(n)

def complex_list_node_clone(head):
    """    
    :param head: origin head
    :return:copy head 
    """
    sham_head = ComplexListNode(0)
    new_node = sham_head
    node = head
    reflect = {}
    while node:
        new_node.next = ComplexListNode(node.val)
        new_node = new_node.next
        reflect[node] = new_node
        node = node.next
    node = head
    new_node = sham_head.next
    while node:
        if node.sibling:
            new_node.sibling = reflect[node.sibling]
        node = node.next
        new_node = new_node.next
    return sham_head.next

思路3:时间复杂度:O(n),空间复杂度:O(11)

def complex_list_node_clone_2(head):
    """
    :param head: origin head
    :return:copy head
    """
    node = head
    while node:
        new_node = ComplexListNode(node.val)
        node.next, node = new_node, node.next
        new_node.next = node
    node = head
    while node:
        if node.sibling:
            node.next.sibling = node.sibling.next
        node = node.next.next
    node = head
    copy_head = head.next
    while node.next:
        node.next, node = node.next.next, node.next
    return copy_head

思考

  1. 思路3其实和思路2异曲同工,就是建立新旧节点的映射关系,以便处理sibling属性,而不用再次从头查找。思路2采用额外哈希表使查询时间为O(1),思路3则将新节点特别的安排为旧节点的Next,这样映射关系即为new_node = node.next 也是O(1)。

同样的题目

LeetCode 138. 复制带随机指针的链表

代码

# Definition for singly-linked list with a random pointer.
# class RandomListNode(object):
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None

class Solution(object):
    def copyRandomList(self, head, hash_table={}):
        """
        :type head: RandomListNode
        :rtype: RandomListNode
        """
        if not head:
            return None
        if head in hash_table:
            return hash_table[head]
        hash_table[head] = RandomListNode(head.label)
        hash_table[head].random = self.copyRandomList(head.random, hash_table)
        hash_table[head].next = self.copyRandomList(head.next, hash_table)
        return hash_table[head]

分析

  1. 上面的代码是别人的解法。很有意思因此分享
  2. 他的思路很特别,不是分步解决next 和 sibling属性,而是在一次遍历中解决。
    具体操作如下:
    1. 遍历链表,对于一个节点一次性设置完next和sibiling属性,将设置好的节点存入字典
    2. 对于next和sibling这两条支链,都递归设置,直到遇到设置好的节点或者链表到头。
    3. 在字典中出现的节点,意味着此节点以后的所有节点都已经被设置完毕。
  3. 这份代码采用了递归,十分简洁。基本思路也比较清晰,就是只要next和sibling还未配置就一路配置到配置完成为止。哈希表记录是否配置过用来防止死循环。

猜你喜欢

转载自blog.csdn.net/u013908099/article/details/86491966
今日推荐