
可以用 Floyd 判圈算法(龟兔赛跑)解决,通过模拟数组的循环链表结构,找到环的入口即为重复的数字,时间复杂度 O(n),空间复杂度 O(1)。
Floyd 判圈算法的核心是将数组视为一个循环链表:
k 的节点,其下一个节点索引为 k-1(即 arr[k-1])。通过快慢指针(慢指针每次走 1 步,快指针每次走 2 步)检测环:
类比:想象一群人在跑圈,慢跑的人(慢指针)和快跑的人(快指针),若圈上有入口(环),快跑的人会先追上慢跑的人,然后从起点和相遇点同时出发,再次相遇的位置就是入口(重复数字)。
| 方法 | 定义 | 时间复杂度 | 空间复杂度 | 适用场景 | 注意点 |
|---|---|---|---|---|---|
| Floyd判圈法 | 将数组视为循环链表,用快慢指针找环入口 | O(n) | O(1) | 数组长度 n+1,元素 1~n,有重复 | 需数组至少有一个重复,元素值在 1~n |
| 排序后找相邻重复 | 先排序数组,再检查相邻元素是否相等 | O(n log n) | O(1)(原地排序)或 O(n)(复制数组) | 空间要求严格时 | 时间复杂度较高,不满足 O(n) |
| 哈希表法 | 用哈希表记录每个数字是否出现过 | O(n) | O(n) | 空间允许时 | 空间复杂度不符合题目要求 |
数组 arr = [3,1,3,4,2](长度 5+1=6,数字 1~4,重复 3):
slow=0,快指针 fast=0。slow = arr[0]=3 → slow=2;fast = arr[arr[0]]=arr[3]=4 → fast=4;slow = arr[2]=3 → slow=2;fast = arr[arr[4]]=arr[2]=3 → fast=3;slow = arr[2]=3 → slow=2;fast = arr[arr[3]]=arr[4]=2 → fast=2;slow=fast=2,第一次相遇(值为 3?不对,实际相遇在索引 2,值为 3,正确)。slow=0,快指针 fast=arr[0]=3。slow = arr[0]=3 → slow=2;fast = arr[arr[3]]=arr[4]=2 → fast=2;slow = arr[2]=3 → slow=2;fast = arr[arr[2]]=arr[3]=4 → fast=4;slow=fast=2,相遇(值为 3),即重复数字。面试官您好,这个问题可以用 Floyd 判圈算法(龟兔赛跑算法)解决。核心思路是将数组视为一个循环链表,每个元素的值作为下一个节点的索引(因为数组元素是 1~n,索引从 0 开始,所以元素值为 k 的节点指向索引 k-1)。当存在重复数字时,链表形成环。用快慢指针检测环:慢指针每次走 1 步,快指针每次走 2 步,直到两者相遇。相遇后,重新初始化慢指针为 0,快指针指向数组第一个元素(索引 0),再次移动直到相遇,此时的值就是重复的数字。具体步骤:1. 初始化慢指针 slow 和快指针 fast 都指向数组第一个元素(索引 0);2. 循环移动指针,直到 slow == fast;3. 重新初始化 slow=0,fast=arr[0];4. 再次循环直到 slow == fast,结果即为重复数字。时间复杂度 O(n),空间复杂度 O(1),满足题目要求。