当前位置: 首页 > article >正文

Swift 解锁 LeetCode 热门难题:不改数组也能找出重复数字?

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

文章目录

    • 摘要
    • 描述
    • 题解答案
    • 题解代码分析
      • 解读:
    • 示例测试及结果
    • 时间复杂度
    • 空间复杂度
    • 总结
    • 实际场景类比
    • 可运行 Demo(Swift Playground)
    • 未来展望

摘要

在数组中找出唯一的重复数字,听起来像一道简单的题目,但如果你不能修改原数组、不能使用额外空间,挑战就变得很有意思了。本文通过 Swift 实现 LeetCode 第 287 题《寻找重复数》的题解,并结合实际编码场景详细拆解背后的逻辑推理过程,帮你真正掌握这道经典的算法题。

描述

题目要求你在一个包含 n + 1 个整数的数组中找到一个重复的数。这些数的取值范围是 [1, n],而且保证 只有一个数字重复,可能重复多次

但它还加了一些限制:

  • 数组不能修改(也就是只读)
  • 空间复杂度得是常数级 O(1)
  • 尽可能做到时间复杂度为线性 O(n)

看起来挺棘手?别急,下面我们一步一步来拆解。

题解答案

常见的思路有三种:

  1. 暴力法 / 哈希法(不能用,违反空间复杂度)
  2. 排序 + 遍历(不能用,违反不能修改数组)
  3. 快慢指针(可以用,经典的“链表找环”变体)

我们要用的是第三种方法,也叫 Floyd 判圈算法。

思路是把数组元素看成指针,nums[i] 代表指向下一个元素的索引,就像一个链表。如果有重复数字,就一定会有一个“环”。

题解代码分析

func findDuplicate(_ nums: [Int]) -> Int {var slow = nums[0]var fast = nums[0]// 第一阶段:找相遇点repeat {slow = nums[slow]fast = nums[nums[fast]]} while slow != fast// 第二阶段:找入口(重复的数字)slow = nums[0]while slow != fast {slow = nums[slow]fast = nums[fast]}return slow
}

解读:

  • 第一次 while 循环找的是两个指针在环里相遇的那个位置。我们先从 nums[0] 开始,slow 每次走一步,fast 每次走两步,像跑圈一样,最终肯定会在环里相遇。
  • 第二次 while 循环是经典的“找环入口”,我们让一个指针从开头出发,另一个从相遇点出发,每次走一步,再次相遇的点就是重复数字。

示例测试及结果

let test1 = [1, 3, 4, 2, 2]
print(findDuplicate(test1))  // 输出: 2let test2 = [3, 1, 3, 4, 2]
print(findDuplicate(test2))  // 输出: 3let test3 = [3, 3, 3, 3, 3]
print(findDuplicate(test3))  // 输出: 3

无论重复的是谁,只要有重复,这个算法就能找出来,效率也很高。

时间复杂度

  • 整体是 O(n),因为我们最多只跑两次遍历,而且每次最多走 n 步。

空间复杂度

  • O(1),只用了两个变量 slowfast,没有开任何额外空间。

总结

这题乍一看像是“简单查重”,实则考验对链表结构与指针遍历逻辑的理解。如果你碰到限制不能修改数组、不能用额外空间的情况,这种借助“指针构造隐含链表”的技巧就非常值得掌握。

而且这种技巧在很多系统设计里也很实用,比如检测日志流的循环引用、追踪用户路径中的重复操作等等。

实际场景类比

想象一下你在做用户路径分析,用户访问路径用数组表示 [页面1, 页面2, 页面3, 页面2, 页面4],你希望知道哪个页面用户又返回访问了。

你不能改动原始日志(只读),也不能复制一份数据再做处理(节省内存),这时候就可以考虑类似的“快慢指针找环”方式来识别重复跳转的路径。

可运行 Demo(Swift Playground)

import Foundationfunc findDuplicate(_ nums: [Int]) -> Int {var slow = nums[0]var fast = nums[0]repeat {slow = nums[slow]fast = nums[nums[fast]]} while slow != fastslow = nums[0]while slow != fast {slow = nums[slow]fast = nums[fast]}return slow
}let sample = [1, 4, 6, 2, 5, 3, 6]
print("重复数字是:\(findDuplicate(sample))")

未来展望

这个题是很多“限制场景下查重”的代表题,我们可以往更复杂的方向去探索:

  • 如何在海量数据(分布式系统)中查找重复?
  • 如果有多个重复的数字,又该如何扩展这类算法?
  • Swift 中的指针式遍历,还有哪些地方能发挥类似作用?
http://www.lryc.cn/news/2398583.html

相关文章:

  • 2025年微信小程序开发:趋势、最佳实践与AI整合
  • 【深度学习】15. Segment Anything Model (SAM) :基于提示的分割新时代
  • Java从入门到精通 - 常用API(一)
  • SQL 筛选出在表1但不在表2中的数据
  • MATLAB实战:实现数字调制解调仿真
  • ccf中学生计算机程序设计入门篇课后题p164页test(1)-2 输入一个数,统计这个数二进制中1的个数
  • 实现Cursor + Pycharm 交互
  • C++标准模板库
  • dvwa6——Insecure CAPTCHA
  • 【机器学习及深度学习】机器学习模型的误差:偏差、方差及噪声
  • 【学习笔记】On the Biology of a Large Language Model
  • 飞腾D2000,麒麟系统V10,docker,ubuntu1804,小白入门喂饭级教程
  • 星野录(博客系统)测试报告
  • 使用 Java 实现一个简单且高效的任务调度框架
  • 2022—2025年:申博之路及硕士阶段总结
  • 项目执行中缺乏灵活应对机制,如何增强适应性?
  • Agentic Workflow是什么?Agentic Workflow会成为下一个AI风口吗?
  • 大模型模型推理的成本过高,如何进行量化或蒸馏优化
  • BUUCTF[极客大挑战 2019]EasySQL 1题解
  • Css样式中设置gap: 12px以后左右出现距离问题解析
  • MySQL问题:count(*)与count(1)有什么区别
  • 大模型 提示模板 设计
  • excel表格记账 : 操作单元格进行加减乘除 | Excel中Evaluate函数
  • 20250602在荣品的PRO-RK3566开发板的Android13下的uboot启动阶段配置BOOTDELAY为10s
  • 如何合理设计缓存 Key的命名规范,以避免在共享 Redis 或跨服务场景下的冲突?
  • Trae CN IDE自动生成注释功能测试与效率提升全解析
  • 让AI弹琴作曲不再是梦:Python+深度学习玩转自动化音乐创作
  • C++概率论算法详解:理论基础与实践应用
  • ssh登录wsl2
  • 黑马Java面试笔记之 消息中间件篇(Kafka)