LeetCode 287. 寻找重复数(不修改数组 + O(1) 空间)

287. 寻找重复数

📌 题目描述

给定一个包含 n + 1 个整数的数组 nums,其所有数字都在区间 [1, n] 范围内(包含 1 和 n)。由于数组中包含 n + 1 个数,而数的取值范围只有 n 个,因此至少存在一个重复的数

请你返回这个唯一重复的数

❗ 限制条件

  • 不能修改数组(不能排序或哈希)

  • 只使用常量级空间(不能使用额外的集合)

  • 时间复杂度 < O(n²) ,理想为 O(n)

🧠 解法:快慢指针(Floyd 判圈算法)

我们将数组视为一个链表,数组的下标是链表的节点编号,元素值是链表的"指针"------即跳转的位置。

复制代码
例如:nums = [1, 3, 4, 2, 2]
可看作链表:
0 → 1 → 3 → 2 → 4 → 2 → 4 → 2 → ...

重复数字造成了"环",问题转换为:**找环的入口**

✅ Floyd 算法分两步:

第一步:快慢指针相遇(找环中某个点)
python 复制代码
slow = nums[0]
fast = nums[0]

# 快走两步,慢走一步
while True:
    slow = nums[slow]
    fast = nums[nums[fast]]
    if slow == fast:
        break

第二步:从起点再来一次,寻找环的起点(即重复数字)

python 复制代码
slow = nums[0]
while slow != fast:
    slow = nums[slow]
    fast = nums[fast]

此时 slow == fast 即为环的入口,也就是重复数字。

✅ 完整代码

python 复制代码
class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        # 第一步:快慢指针相遇
        slow = nums[0]
        fast = nums[0]
        while True:
            slow = nums[slow]
            fast = nums[nums[fast]]
            if slow == fast:
                break

        # 第二步:找环的入口
        slow = nums[0]
        while slow != fast:
            slow = nums[slow]
            fast = nums[fast]

        return slow

⏱️ 时间复杂度与空间复杂度分析

指标 说明
⏱️ 时间复杂度 O(n),快慢指针最多跑两轮链表
💾 空间复杂度 O(1),只用了几个变量

📌 总结

  • 不能修改原数组 ➜ 排除排序、计数等解法

  • 要求 O(1) 空间 ➜ 排除哈希表

  • 使用链表快慢指针 ➜ 经典技巧,空间压缩到极致!

相关推荐
FAFU_kyp15 小时前
Rust 的 引用与借用
开发语言·算法·rust
执携15 小时前
数据结构 -- 数组(Array)
数据结构
永远都不秃头的程序员(互关)15 小时前
【K-Means深度探索(一)】数据炼金术第一步:从零手撕K-Means聚类算法
算法·kmeans·聚类
我想回家种地15 小时前
算法期末复习
算法
洛豳枭薰15 小时前
List梳理
数据结构·windows·list
rgeshfgreh15 小时前
MPPI算法实战:运动规划新利器
算法
Xの哲學15 小时前
Linux epoll 深度剖析: 从设计哲学到底层实现
linux·服务器·网络·算法·边缘计算
星火开发设计15 小时前
C++ multiset 全面解析与实战指南
开发语言·数据结构·c++·学习·set·知识
小猪咪piggy15 小时前
【leetcode100】回溯
数据结构·算法
m0_6038887116 小时前
More Images, More Problems A Controlled Analysis of VLM Failure Modes
人工智能·算法·机器学习·ai·论文速览