python每日一题【剑指 Offer 35. 复杂链表的复制】

day6-2022.10.30

题目信息来源
作者:Krahets
链接:https://leetcode.cn/leetbook/read/illustration-of-algorithm
来源:力扣(LeetCode)

剑指 Offer 35. 复杂链表的复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

wxy_leetcode_2022-10-22_20-36-06

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

题解一:哈希表

  1. 和普通的链表复制不同,还多了一个random,这意味着在第一轮遍历时不能像普通的链表复制一样,直接复制,因为copy_node的randow可能还没有创建。因为这个必须需要两轮遍历。第一轮遍历,从头到尾创建所有copy_node,第二轮遍历指向next和random
  2. 第二个问题来了,如果我们在第一轮遍历时,保存了原链表和copy链表的头节点,那后续我们可以获得next和copy_next。但怎么获得copy_random呢?或者说,我们怎么根据一个node获得第一轮遍历时创建的相对应的copy_node呢?解决方案时用字典,或者是哈希,创建node-copy_node对,来存储对应关系。这样我们只需要原链表的head就可以陆续获得所有的节点。

知识点

  1. dict.get(key[,value]) :返回指定键的值,如果指定键的值不存在,返回value默认值(默认值可以指定,没有指定就是None),相比较而言 dict[key] 会在 key 不存在时抛出 keyerror 的错误,get 不会。但是 get 的速度要慢一点。这个题里用 get 好一点
  2. 代码的简洁性,主要体现在这几句,本来我写了有7行,其实只需要两行
                mydict[head].next = mydict.get(head.next) # copy_head的next为copy_next
                mydict[head].random = mydict.get(head.random)
"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head: return
        else:
            mydict = {}                         # 保存节点和对应的复制节点
            head_node = head                    # 保存头节点
            # 第一轮遍历,只是把节点和节点的next创建一下,只所以选择分两轮,是因为第一轮时copy的next可能还未创建
            while head:
                mydict[head] = Node(head.val)   # 保存head copy_head键值对
                head = head.next                # 将当前head变为head.next
            head = head_node
            # 第二轮遍历,发现不是很简单,因为next是Node类型,第二轮遍历,不管是copy还有原来的都不好找
            # 查看了解析,似乎使用字典存储head和对应的copy_head可以方便查找
            while head:
                mydict[head].next = mydict.get(head.next) # copy_head的next为copy_next
                mydict[head].random = mydict.get(head.random)
                head = head.next

            return mydict[head_node]

题解二:拼接+拆分

要注意while后面跟的值

"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head:return
        now = head                      # 获得head
        # 第一轮遍历,插入
        while now:
            node = Node(now.val)        # 插入now的复制节点
            node.next = now.next        # 将now的复制节点的next复制为now的next,next必须指定使链表连接起来
            now.next = node             # now.next变成复制节点,random暂且不赋值
            now = node.next
        # 第二轮遍历,指向randow,这个时候还不能拆,因为有可能randow指向链表的前面部分节点
        now = head                      # 获得head
        while now:
            node = now.next             # 获得插入的节点
            if now.random:
                node.random = now.random.next# randow为now的random后面的插入节点
            now = node.next
        # 第三轮遍历,拆
        now = head
        node = copy_head = head.next
        # 这里要用node.next来确定是否有下一个节点,now.next没拆之前是一定存在的
        while node.next:
            now.next = node.next
            now = now.next
            node.next = now.next
            node = node.next
        return copy_head
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

piukaty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值