把值视为 next 指针,Floyd 找环入口即为重复数。
OJ: leetcodecn
题目 ID: find-the-duplicate-number
难度:提高+/省选-
标签:快慢指针链表技巧
日期: 2026-07-29 13:04
题意
在 n+1 个元素(值域 [1,n])中找重复数,不修改数组,O(1) 空间。
思路
把 nums[i] 视为从 i 到 nums[i] 的 next 指针,数组构成一个有环链表(重复值导致两个节点指向同一后继)。Floyd 快慢指针找环入口即为重复数。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int findDuplicate(vector<int> &nums) {
int slow = nums[0], fast = nums[0];
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
slow = nums[0];
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n);
for (int &x : a)
cin >> x;
cout << Solution().findDuplicate(a) << '\n';
return 0;
}python
#!/usr/bin/env python3
from typing import List
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
slow = 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
def main():
n = int(input())
a = list(map(int, input().split()))
print(Solution().findDuplicate(a))
if __name__ == "__main__":
main()复杂度
- 时间复杂度:
。 - 空间复杂度:
。
总结
把数组值视为 next 指针是本题的关键映射。重复数意味着两个位置指向同一个后继,形成环。Floyd 找环入口的证明与链表环检测完全相同。