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 基础为核心的技术内容,也整理收集优秀的学习资料。

相关推荐
得物技术11 小时前
得物 iOS 启动优化之 Building Closure
ios·性能优化
爱爬山的老虎17 小时前
【面试经典150题】LeetCode121·买卖股票最佳时机
数据结构·算法·leetcode·面试·职场和发展
雾月5517 小时前
LeetCode 914 卡牌分组
java·开发语言·算法·leetcode·职场和发展
想跑步的小弱鸡17 小时前
Leetcode hot 100(day 4)
算法·leetcode·职场和发展
Fantasydg17 小时前
DAY 35 leetcode 202--哈希表.快乐数
算法·leetcode·散列表
jyyyx的算法博客17 小时前
Leetcode 2337 -- 双指针 | 脑筋急转弯
算法·leetcode
ゞ 正在缓冲99%…18 小时前
leetcode76.最小覆盖子串
java·算法·leetcode·字符串·双指针·滑动窗口
惊鸿.Jh18 小时前
【滑动窗口】3254. 长度为 K 的子数组的能量值 I
数据结构·算法·leetcode
goto_w19 小时前
uniapp上使用webview与浏览器交互,支持三端(android、iOS、harmonyos next)
android·vue.js·ios·uni-app·harmonyos
想跑步的小弱鸡1 天前
Leetcode hot 100(day 3)
算法·leetcode·职场和发展