数组中找重复值
int findDuplicate(vector<int>& nums) {
// 由鸽笼原理,一定有重复
// 把nums[i]看做下标i的next下标,相当于链表的next指针,
// 找重复的数变成链表中找环的入口点,快慢指针法
int fast = 0, slow = 0;
while (true) {
fast = nums[nums[fast]];
slow = nums[slow];
if (fast == slow) break;
}
fast = 0;
while (fast != slow) {
fast = nums[fast];
slow = nums[slow];
}
return fast;
}
循环数组中找单向循环
快慢指针找循环,将够不成循环的路径上的点都设为0。
bool circularArrayLoop(vector<int>& nums) {
const int N = nums.size();
// 快慢指针找循环
for (int i = 0; i < N; i++) {
if (nums[i] == 0) continue; // 无循环路径上的点已设为0
// 看从i出发是否构成单向循环
int fast = i, slow = i;
while (true) {
int next = getNext(fast, nums);
if (nums[i] * nums[next] < 0) break; // 循环方向变了
fast = next, next = getNext(fast, nums);
if (nums[i] * nums[next] < 0) break;
fast = next;
slow = getNext(slow, nums);
if (fast == slow) { // 有环
if (getNext(fast, nums) == fast) break; // 循环长度==1
return true;
}
}
// 至此从i出发够不成循环,将路径上的点都设为0
int sign = nums[i], curr = i;
while (sign * nums[curr] > 0) {
int next = getNext(curr, nums);
nums[curr] = 0;
curr = next;
}
}
return false;
}
int getNext(int idx, vector<int> &nums) {
const int N = nums.size();
int ans = (idx + nums[idx]) % N;
if (ans < 0) ans += N;
return ans;
}
更多快慢指针的例子见链表