题目描述
blablabla
样例
blablabla
算法1
(追击) O(n)
前面也有一篇O(n)的做法, 但是证明不太正确
首先题目是必定存在环, 每个位置的i指向ai
也就是 0−>a[0]−>a[a[0]]−>…−>x−>a[x]−>a[a[x]]−>..−>a[x]
我们从x这个位置进入环a[x], 能形成环, 在环内必然存某个位置j,a[j]−>a[x]
故现在存在两个位置都指向a[x] 故ax和aj相同, 都指向位置a[x]
设两个快慢指针x,y, 当相遇时为a[x]这个位置偏移d步, 设链长为n, 环长m, 则
Sx=n+kx×m+d,Sy=n+ky×m+d
且Sx=2×Sy, 则
(kx−ky)×m=n+d, 因为快指针速度时慢指针的两倍
当慢指针走完一圈, 快指针走完两圈, 级快指针必能在慢指针走完一圈之内追上慢指针(但我们并不知道kx−ky)
然后我们再把快指针x放回远点, 再次追击(这次两个指针速度都为1), 当快指针走到环的入口时Sx=n
S,x=n,S,y=n+Sy=n+ky×m+n+d
别忘了 (kx−ky)×m=n+d
故 S,y=n+kx×m 即当x刚入环的时候2者相遇, 此位置即是a[x]
时间复杂度
参考文献
C++ 代码
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int x = 0, y = 0;
for (; !x || (x ^ y); x = nums[nums[x]], y = nums[y]);
for (x = 0; x ^ y; x = nums[x], y = nums[y]);
return x;
}
};
这道题这块不是很适用吧,当num[0]=0的时候或者有个类似于[ 2 3 1 …]这种小环的时候都有问题,只适合内部第一个出现你上面证明的那种情况的环,因为这个数组里面可能不止一个环
牛!