[剑指offer] 35.复杂链表的复刻

题目

请实现一个函数可以复制一个复杂链表。
在复杂链表中,每个结点除了有一个指针指向下一个结点外,还有一个额外的指针指向链表中的任意结点或者null。
要求返回这个链表的 深拷贝。

我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示Node.val 的整数.
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null.
在这里插入图片描述
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

思路

哈希表

新旧节点交错法

第一次遍历链表,把每个节点都复制一个连在原节点的后面,旧链表:A-> B-> C->None 新链表:A-> A’-> B-> B’-> C-> C’->None
第二次遍历链表,对于有random的节点,令其新节点指向random的新节点。也就是 p.next.random=p.random.next。
第三次遍历链表,使用虚拟头结点,然后在遍历过程中把这些新节点拎出来,抛弃原节点。

时间复杂度:O(N)
空间复杂度:O(1)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

错误片段

错误1:连接新节点和新节点对应的random时,遍历链表需要跳着找带有random的原节点,否则刚连上的random的新节点也被误操作,造成错乱。

 # link
 ptr=head
 while ptr:
     if ptr.random:
         ptr.next.random=ptr.random.next
     ptr=ptr.next.next   ### 容易错!不是ptr=ptr.next !!

错误2:You can’t modify the original list!
如果最后直接返回head.next则报错。我们返回深拷贝,不能更改原链表,因此在最开始拆分链表的时候,需要定义两个变量赋值为head.next,一个用来遍历链表找出新节点,一个用来标记新链表的头节点也就是head.next以便最后返回。

错误3:如果在第二句中ptr_old变为None,那么第三句就会报错。:所以应该,在第一句执行完后,先判断ptr_old.next是否为None,再继续执行ptr_new.next的赋值问题。

        # 错误版本1
		while ptr_old:
            ptr_old.next=ptr_new.next
            ptr_old=ptr_old.next
            ptr_new.next=ptr_old.next
            ptr_new=ptr_new.next
            
        # 正确版本1
        while ptr_old:
            ptr_old.next=ptr_new.next
            if ptr_old.next:
                ptr_old=ptr_old.next
                ptr_new.next=ptr_old.next
                ptr_new=ptr_new.next
            else:
                break 
                # 直接 break可以代替下面两行
                # ptr_old=ptr_old.next
                # ptr_new.next=None
                
        # 正确版本2
        while ptr_old:
            ptr_old.next=ptr_old.next.next
            if ptr_old.next:
                ptr_new.next=ptr_new.next.next
            else:
                ptr_new.next=None
            ptr_old=ptr_old.next
            ptr_new=ptr_new.next
完整代码
"""
# Definition for a Node.
class Node:
    def __init__(self, x, next=None, random=None):
        self.val = int(x)
        self.next = next
        self.random = random
"""
class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: Node
        :rtype: Node
        """
        if not head:
            return head
        # clone and insert  
        ptr=head
        while ptr:
            clone=Node(ptr.val,next=None, random=None)
            clone.next=ptr.next
            ptr.next=clone
            ptr=clone.next
        # link
        ptr=head
        while ptr:
            if ptr.random:
                ptr.next.random=ptr.random.next
            ptr=ptr.next.next   ### 容易错!不是ptr=ptr.next !!
        
        # extract
        ptr_old=head
        ptr_new=head.next
        ptr_out=head.next
        while ptr_old:
            ptr_old.next=ptr_old.next.next
            if ptr_old.next:
                ptr_new.next=ptr_new.next.next
            else:
                ptr_new.next=None
            ptr_old=ptr_old.next
            ptr_new=ptr_new.next
        return ptr_out
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值