链表里环的入口节点
用两个指针 first,secondfirst,second 分别从起点开始走,firstfirst 每次走一步,secondsecond 每次走两步。
如果过程中 secondsecond 走到null,则说明不存在环。否则当 firstfirst 和 secondsecond 相遇后,让 firstfirst 返回起点,secondsecond 待在原地不动,然后两个指针每次分别走一步,当相遇时,相遇点就是环的入口。
int findDuplicate(vector<int>& nums) {//双指针发,特别好用
int fast=0,slow=0;
while(true){
fast=nums[nums[fast]];
slow=nums[slow];
if(fast==slow){
slow=0;
while(fast!=slow){
fast=nums[fast];
slow=nums[slow];
}
return slow;
}
}
return -1;
}
引申:
双指针还可以用于很多的地方,比如数组区间问题,可以定义两个指针以制定的速度按题目要求走,可以大大减少时间复杂度
比如把一个数组里的0都移到最后就可以用两个指针而不用去开辟新的数组。
void moveZeroes(vector<int>& nums) {
int i=0,j=0;
int n=nums.size();
while(i<n&&j<n){
while(i<n&&nums[i]!=0){//从前往后走!=的放到右边,从后往前走等于的放在右边
i++;
}
j=max(i,j);
while(j<n&&nums[j]==0){
j++;
}
if(i<n&&j<n){
swap(nums,i,j);
}
}
}