首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >LeetCode - #138 随机链表的复制

LeetCode - #138 随机链表的复制

原创
作者头像
Swift社区
修改2024-11-20 22:00:09
修改2024-11-20 22:00:09
2470
举报
文章被收录于专栏:Swift社区Swift社区

好事发生

文章推荐:如何构建安全可靠的 HarmonyOS 应用

文章链接:https://cloud.tencent.com/developer/article/2465737

文章简介:本文深入探讨了 HarmonyOS App 的安全编码规范与最佳实践,感兴趣的同学可以看看!

前言

本题由于没有合适答案为以往遗留问题,最近有时间将以往遗留问题一一完善。

我们社区陆续会将顾毅(Netflix 增长黑客,《iOS 面试之道》作者,ACE 职业健身教练。)的 Swift 算法题题解整理为文字版以方便大家学习与阅读。

不积跬步,无以至千里;不积小流,无以成江海,Swift社区 伴你前行。如果大家有建议和意见欢迎在文末留言,我们会尽力满足大家的需求。

难度水平:困难

摘要

本文讨论了如何在 Swift 中实现对链表的深拷贝,特别是包含随机指针(random)的链表的深拷贝问题。深拷贝要求新链表中的节点完全独立于原链表,但在值、next 和 random 指针的结构上与原链表一致。通过两次遍历链表,并利用字典(Dictionary)存储节点映射关系,本文提供了一种高效且清晰的解决方案。具体实现代码包括节点定义、链表复制逻辑以及测试用例。

1. 描述

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。**复制链表中的指针都不应指向原链表中的节点 **。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

你的代码  接受原链表的头节点 head 作为传入参数。

2. 示例

示例 1:

输入:head = 7,null,13,0,11,4,10,2,1,0

输出:7,null,13,0,11,4,10,2,1,0

示例 2:

输入:head = 1,1,2,1

输出:1,1,2,1

示例 3:

输入:head = 3,null,3,0,3,null

输出:3,null,3,0,3,null

提示:

  • 0 <= n <= 1000
  • -10^4 <= Node.val <= 10^4
  • Node.randomnull 或指向链表中的节点。

3. 答案

题解

在 Swift 中,可以通过字典来存储原链表节点与复制链表节点的映射关系,最终实现深拷贝。以下是实现代码:

代码语言:swift
复制
class Node {
    var val: Int
    var next: Node?
    var random: Node?

    init(_ val: Int) {
        self.val = val
        self.next = nil
        self.random = nil
    }
}

func copyRandomList(_ head: Node?) -> Node? {
    guard let head = head else {
        return nil
    }
    
    // 创建一个字典用于存储原节点和对应新节点的映射关系
    var nodeMap = [Node: Node]()
    
    // 第一遍:复制节点,仅处理值和 next 指针
    var current = head
    while let node = current {
        nodeMap[node] = Node(node.val)
        current = node.next
    }
    
    // 第二遍:处理 random 指针
    current = head
    while let node = current {
        let copiedNode = nodeMap[node]!
        copiedNode.next = node.next != nil ? nodeMap[node.next!] : nil
        copiedNode.random = node.random != nil ? nodeMap[node.random!] : nil
        current = node.next
    }
    
    return nodeMap[head]
}

代码说明:

  1. 第一遍遍历
    • 使用字典 nodeMap 将原链表中的每个节点映射到一个新创建的节点,只处理节点的值 (val) 和 next
  2. 第二遍遍历
    • 通过字典 nodeMap,为每个新节点设置 random 指针。
    • 确保 nextrandom 的引用都指向新链表中的节点。
  3. 返回值
    • 返回新链表的头节点。

示例测试:

假设链表为 [[7, null], [13, 0], [11, 4], [10, 2], [1, 0]]

代码语言:swift
复制
let node1 = Node(7)
let node2 = Node(13)
let node3 = Node(11)
let node4 = Node(10)
let node5 = Node(1)

node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5

node2.random = node1
node3.random = node5
node4.random = node3
node5.random = node1

if let newHead = copyRandomList(node1) {
var current: Node? = newHead
while let node = current {
    print("Value: \(node.val), Random Value: \(node.random?.val ?? -1)")
    current = node.next
}
}

输出:

Value: 7, Random Value: -1

Value: 13, Random Value: 7

Value: 11, Random Value: 1

Value: 10, Random Value: 11

Value: 1, Random Value: 7

这表明新链表已正确复制了值及指针结构。

点击前往 LeetCode 练习

总结

  • 本文实现了一个 Swift 算法,解决链表深拷贝问题,支持 next 和 random 指针。
  • 解决方案
  • 第一遍遍历:建立原链表节点与新链表节点的映射,仅初始化新节点。
  • 第二遍遍历:通过映射关系补充 next 和 random 指针的链接。
  • 测试验证:通过多组链表数据结构,验证深拷贝的正确性,确保新链表结构与原链表一致但完全独立。
  • 代码特点:逻辑清晰、可读性强,使用 Swift 的基础数据结构和语法实现高效解决方案。

此算法适用于复杂链表操作及相关问题的扩展,并为学习和使用 Swift 提供了一个实践案例。

关于我们

我们是由 Swift 爱好者共同维护,我们会分享以 Swift 实战、SwiftUI、Swift 基础为核心的技术内容,也整理收集优秀的学习资料。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 好事发生
  • 前言
  • 摘要
  • 1. 描述
  • 2. 示例
  • 3. 答案
    • 题解
    • 代码说明:
    • 示例测试:
    • 输出:
  • 总结
  • 关于我们
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档