算法二十天
第九天
寻找重复数
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
示例 2:
输入:nums = [3,1,3,4,2]
输出:3
提示:
1 <= n <= 10^5
nums.length == n + 1
1 <= nums[i] <= n
nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-duplicate-number
首先想到的是利于哈希表记录每个数字的出现个数,如果大于1返回,但是空间复杂度为O(n),不符合题意。这里的数组很特别,num[i]<=n,n.length==n+1所以可以将数组中的数当成指针,譬如{1,3,2,1},nums[0]中是下一个数的地址,依次类推,最后总会有环出现
于是问题转化成了求链表中是否有环并且判断环的入口
假设环长为 LL,从起点到环的入口的步数是 aa,从环的入口继续走 bb 步到达相遇位置,从相遇位置继续走 cc 步回到环的入口,则有
b+c=Lb+c=L,其中 LL、aa、bb、cc 都是正整数。根据上述定义,慢指针走了 a+ba+b 步,快指针走了
2(a+b)2(a+b) 步。从另一个角度考虑,在相遇位置,快指针比慢指针多走了若干圈,因此快指针走的步数还可以表示成
a+b+kLa+b+kL,其中 kk 表示快指针在环上走的圈数。联立等式,可以得到2(a+b)=a+b+kL 2(a+b)=a+b+kL
解得 a=kL-ba=kL−b,整理可得
a=(k-1)L+(L-b)=(k-1)L+c a=(k−1)L+(L−b)=(k−1)L+c
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/find-the-duplicate-number/solution/xun-zhao-zhong-fu-shu-by-leetcode-solution/ 来源:力扣(LeetCode)
所以当slow指针从起点开始走的化再次相遇即是入口,这道题很难想到这mo巧的答案,毕竟题目的条件很巧合。
#include<bits/stdc++.h>
using namespace std;
int f(vector<int>& temp) {
int slow=temp[0];
int fast=temp[temp[0]];
while(slow!=fast)
{
slow=temp[slow];
fast=temp[temp[fast]];
}
slow=0;
while (slow != fast) {
slow = temp[slow];
fast = temp[fast];
}
return slow;
}
int main()
{
vector<int> temp={
1,3,4,2,5,2,6,7};
cout<<f(temp);
}