跨列表遍历的终极技巧:用 Swift 实现 Zigzag Iterator 超干净逻辑!

在这里插入图片描述
在这里插入图片描述

文章目录

    • 摘要
    • 描述
    • 题解答案
    • 题解代码分析
      • Swift 实现:可扩展版本
    • 示例测试及结果
      • 示例输入:
      • 输出结果:
    • 时间复杂度
    • 空间复杂度
    • 总结
    • 未来展望

摘要

在日常开发或算法场景中,我们经常会遇到对多个列表交替读取的需求,比如分页显示、轮播切换、双端合并等等。而 LeetCode 281 的锯齿迭代器(Zigzag Iterator)正是这样一个经典问题的抽象:给定两个或多个数组,实现一种可以“轮流”读取它们的迭代器。

这篇文章将以 Swift 为语言,带你逐步构建一个高效、优雅的锯齿迭代器,并结合示例讲解其背后的核心思想和实现细节。

描述

题目要求我们实现一个类 ZigzagIterator,它支持以下操作:

  • next():返回当前元素,并将指针移到下一个要访问的元素。

  • hasNext():判断是否还有元素可以返回。

假设我们有两个向量:

v1 = [1, 2]
v2 = [3, 4, 5, 6]

迭代器的遍历顺序应该是:[1, 3, 2, 4, 5, 6],即在两个数组之间来回交替,若某个数组访问完毕,就跳过它。

题解答案

我们可以用一个队列(或数组)来存储数组的迭代器。当调用 next() 时,就从当前队列中取出一个迭代器访问其元素,并将它重新放回队尾(如果还有剩余元素)。

这个方法的优点是:结构清晰,方便拓展到多个数组(不仅仅是两个)。

题解代码分析

Swift 实现:可扩展版本

class ZigzagIterator {
    private var queue: [IndexingIterator<[Int]>]

    init(_ v1: [Int], _ v2: [Int]) {
        queue = []
        if !v1.isEmpty { queue.append(v1.makeIterator()) }
        if !v2.isEmpty { queue.append(v2.makeIterator()) }
    }

    func next() -> Int {
        var iter = queue.removeFirst()
        let value = iter.next()!
        if let peek = iter.next() {
            // 将当前值和剩余值打包进新的迭代器
            queue.append(([peek] + Array(iter)).makeIterator())
        } else {
            // 当前迭代器已经没了就不放回去了
        }
        return value
    }

    func hasNext() -> Bool {
        return !queue.isEmpty
    }
}

示例测试及结果

示例输入:

let v1 = [1, 2]
let v2 = [3, 4, 5, 6]
let zigzag = ZigzagIterator(v1, v2)

while zigzag.hasNext() {
    print(zigzag.next(), terminator: " ")
}

输出结果:

1 3 2 4 5 6

说明:

  • 首先从 v11,然后 v23

  • 接着 v12,再从 v24

  • 最后 v2 剩余的 56 顺序输出

时间复杂度

  • 初始化阶段: O(1)(只做了一些数组和迭代器的创建)

  • next() 调用次数: 每次为 O(1),因为只处理当前一个迭代器

  • 整体遍历完成: O(n),其中 n 是总元素数

空间复杂度

  • 最坏情况: O(k),其中 k 是数组数量

  • 存储的是 k 个迭代器或下标,不随数组长度增长

总结

这道题考验的是“多路轮询”的实现能力,非常适合用来练习如何管理多个数据源的遍历。借助 Swift 的迭代器,我们不仅写出了清晰的逻辑,也方便扩展到多个数组的情况。

而这个锯齿遍历的方式,在实际中同样有很多用途,比如:

  • 多线程轮询任务执行器

  • 多数据源拼接输出

  • UI 轮播图(多个来源交替展示)

未来展望

如果我们将这个类扩展为支持不定数量的输入数组,只需要在初始化时将 [[Int]] 转成一组迭代器,并在 next() 中动态维护它们。甚至还可以实现延迟加载,提升内存效率。

此外,结合协程或异步序列,我们还能构建更智能的数据流合并器,比如分页数据的异步拉取与渲染等。

你可能感兴趣的:(Swift,swift,开发语言,ios)