核心思想
快慢指针的核心思想是利用两个移动速度不同的指针(通常快指针每次走两步,慢指针每次走一步,在遍历过程中通过他们的位置关系或相遇情况来解决问题。通常在数组和链表中有应用。(快指针用来探路,慢指针用来定位)
一、快慢指针在链表中的应用
1.判断链表是否有环
通过快慢指针来判断链表是否有环。
思路:创建两个指针slow,fast,遍历链表。slow每次走一步,fast每次走两步,若链表有环,则快慢指针在进环后,快指针总会追上慢指针。若链表无环,则fast走向末尾。
c
bool hasCycle(struct ListNode *head) {
struct ListNode* slow,*fast;
slow = fast = head;
while(fast&&fast->next)
{
slow=slow->next;
fast = fast->next->next;
if(slow==fast)
{
return true;
}
}
return false;
}
拓展问题 :1.为什么一定会相遇,有没有可能会错过,永远追不上,请证明。
2.slow一次走1步,fast一次走3,4,5,步 n步,请证明。
证明:(1)
(2)

结论:一定能追上,N偶数第一轮就追上,N奇数,C-1偶数,第二轮追上。
2.返回链表入环的节点
c
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *slow,*fast;
slow = fast = head;
while(fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow==fast)
{
struct ListNode *meet = slow;
while(meet!=head)
{
meet = meet->next;
head = head->next;
}
return meet;
}
}
return NULL;
}

3.寻找链表的中点
通过快慢指针来返回链表中间节点,或返回第二个中间节点,可以通过快慢指针的方式,fast=2slow。(分为奇数和偶数个节点)
c
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
ListNode* slow, *fast;
slow = fast = head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
4.寻找倒数第k个节点
先让快指针走k步,,然后快慢指针同步移动,当快指针到达末尾时,慢指针指向的即为倒数第k个节点。
c
typedef struct ListNode ListNode;
int kthToLast(struct ListNode* head, int k) {
ListNode *slow,*fast;
slow = fast=head;
while(k--)
{
fast=fast->next;
}
while(fast)
{
slow=slow->next;
fast=fast->next;
}
return slow->val;
}
5.随机链表的复制
c
struct Node* copyRandomList(struct Node* head) {
struct Node *cur = head;
//拷贝节点插入在原节点的后面
while(cur)
{
struct Node *copy = (struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
copy->next = cur->next;
cur->next = copy;
cur = copy->next;
}
//控制random
cur = head;
while(cur)
{
struct Node* copy = cur->next;
if(cur->random==NULL)
{
copy->random=NULL;
}
else{
copy->random = cur->random->next;
}
cur = copy->next;
}
//把拷贝节点取下来尾插成为新链表,然后恢复原链表,不恢复也可以
struct Node* copyhead,*copytail;
copyhead = copytail = NULL;
cur = head;
while(cur)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
if(copytail==NULL)
{
copyhead = copytail = copy;
}
else
{
copytail->next = copy;
copytail = copytail->next;
}
cur->next = next;
cur=next;
}
return copyhead;
}



二、快慢指针在数组中的应用
1.移除元素
在有序数组中,慢指针指向"已处理区间"的末尾,快指针用于探索新元素,当快指针遇到不重复(或不等于目标值)的元素时,将其赋值给慢指针并移动慢指针。
移除数组中的重复元素
c
int removeDuplicates(int* nums, int numsSize) {
int slow = 0;
for(int fast=1;fast<numsSize;fast++)
{
if(nums[fast]!=nums[slow])
{
slow++;
nums[slow]=nums[fast];
}
}
return slow+1;
}