前言:本篇文章十分推荐大家仔细理解,在以后大有用处。
一、快慢指针的初应用
我们直接来看题目,大家可以停下思考后再看后面的解答将会加深理解。
原题出自leetcode
给你单链表的头结点
head
,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
二、解题思路
1.方法一
创建一个指针用来数一下该链表有多少个结点。再创建一个指针移动(m/+1)个位置就是我们要返回的值。
方法一比较简单,我们重点来看方法二。
2.方法二(快慢指针)
使用快慢指针,fast结点为快指针,每次移动两个位置:slow结点为慢指针,每次移动一个位置:因为fast的速度是slow的两倍,因此slow结点始终是在中间位置。
下面是画图来演示:
奇数个结点的情况:
偶数个结点的情况 :
下面就是函数的实现:
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode*fast=head;
struct ListNode*slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
三、快慢指针的变形
有了对快慢指针的初步认识后,我们来看个快慢指针的变形应用:
请看题;
输入一个链表,输出该链表中倒数第k个结点。
输入:1,{1,2,3,4,5}
返回值:{5}
四、解题思路
1.方法一
创建一个指针来数结点的个数记作m,再创建一个结点移动(m-k)个位置就是我们需要的位置。
在测试用例中也有k大于m的情况,我们只需要判断一下即可。
同样,在这里我们主要讲解快慢指针的方法。
2.方法二(快慢指针)
同样的一个fast指针和一个slow指针,在这里我们应该怎么使用这两个指针呢?
快指针应该快多少?
我们可以这样来思考:
在一开始,我们就让 fast 和 slow 相差(k-1)个长度,然后 fast 和 slow 都以 1 的速度前进,那么当 fast 到达终点(最后一个结点) 时,fast 和 slow 仍然相差着(k-1)个长度,此时因为 fast 是站在最后一个结点上,所以 slow 所在的位置即是倒数第 k 个。
举个例子:
有5个结点{1,2,3,4,5},我们要看倒数第2个结点是多少。
下面画图演示:
最后就是代码实现:
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
{
// write code here
struct ListNode* fast=pListHead;
struct ListNode* slow=pListHead;
k--;//代替k-1
//首先让fast先走(k-1)个长度
while(k--&&fast)
{
fast=fast->next;
}
//这里防止k的数目比结点数多
if(fast==NULL)
{
return NULL;
}
//两个结点以相同的速度移动
while(fast->next)
{
fast=fast->next;
slow=slow->next;
}
return slow;
}
四、结语
快慢指针的使用将会在你未来的解题中给你又一解题思路,希望大家能够掌握并熟练使用。
同时,也欢迎大家指出文章中存在的问题。
最后,欢迎大家关注作者,作者会持续更新有趣的代码,在有趣的玩意儿中成长!