LeetCode - #138 随机链表的复制

前言

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

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

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

难度水平:困难

摘要

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

1. 描述

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

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

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

返回复制链表的头节点。

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

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

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

2. 示例

示例 1:

css 复制代码
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例 2:

lua 复制代码
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]

示例 3:

lua 复制代码
输入: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
    }
}

输出:

yaml 复制代码
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 算法,解决链表深拷贝问题,支持 nextrandom 指针。

  • 解决方案

    1. 第一遍遍历:建立原链表节点与新链表节点的映射,仅初始化新节点。
    2. 第二遍遍历 :通过映射关系补充 nextrandom 指针的链接。
  • 测试验证:通过多组链表数据结构,验证深拷贝的正确性,确保新链表结构与原链表一致但完全独立。

  • 代码特点:逻辑清晰、可读性强,使用 Swift 的基础数据结构和语法实现高效解决方案。

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

关于我们

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

相关推荐
Lris-KK2 小时前
力扣Hot100--94.二叉树的中序遍历、144.二叉树的前序遍历、145.二叉树的后序遍历
python·算法·leetcode
2501_915909062 小时前
原生 iOS 开发全流程实战,Swift 技术栈、工程结构、自动化上传与上架发布指南
android·ios·小程序·uni-app·自动化·iphone·swift
2501_915106322 小时前
Comodo HTTPS 在工程中的部署与排查实战(证书链、兼容性与真机抓包策略)
网络协议·http·ios·小程序·https·uni-app·iphone
2501_915909063 小时前
苹果软件混淆与 iOS 代码加固趋势,IPA 加密、应用防反编译与无源码保护的工程化演进
android·ios·小程序·https·uni-app·iphone·webview
2501_916007473 小时前
苹果软件混淆与 iOS 应用加固实录,从被逆向到 IPA 文件防反编译与无源码混淆解决方案
android·ios·小程序·https·uni-app·iphone·webview
坚持编程的菜鸟3 小时前
LeetCode每日一题——螺旋矩阵
c语言·算法·leetcode·矩阵
(●—●)橘子……3 小时前
记力扣2009:使数组连续的最少操作数 练习理解
数据结构·python·算法·leetcode
GalaxyPokemon3 小时前
LeetCode - 1171.
算法·leetcode·链表
iナナ3 小时前
Java优选算法——位运算
java·数据结构·算法·leetcode
Han.miracle4 小时前
数据结构二叉树——层序遍历&& 扩展二叉树的左视图
java·数据结构·算法·leetcode