快慢指针
- 快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢。例如可以让快指针每次沿链表向前移动2,慢指针每次向前移动1次。
快慢指针在链表中的应用
一、环形链表(LeetCode141题)
解题思路
- 如果链表存在环,就好像操场的跑道是一个环形一样。此时让快慢指针都从链表头开始遍历,快指针每次向前移动两个位置,慢指针每次向前移动一个位置;如果快指针到达NULL,说明链表以NULL为结尾,没有环。如果快指针追上慢指针,则表示有环。
代码实现:
bool hasCycle(struct ListNode *head) {
if(head == NULL || head->next == NULL)
return false;
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast != NULL && fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
return true;
}
return false;
}
二、链表中间节点(LeetCode876题)
解题思路
- 定义两个指针,一个快指针fast,一个慢指针slow,快指针一次走两步,慢指针一次走一步,当快指针走到最后,慢指针正好走在中间的位置,此时返回慢指针所在位置即可,注意当链表为空时直接返回头结点即可。
代码实现
struct ListNode* middleNode(struct ListNode* head) {
if(head == NULL || head->next == NULL)
return head;
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast != NULL && fast->next !=NULL)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
三、删除链表倒数第N个节点(LeetCode19题)
解题思路
- 定义两个指针,一个快指针fast,一个慢指针slow,让快指针先走n步,再让快慢指针一起走,当快指针走到链表最后,慢指针正好走在链表的倒数第n-1个位置,此时删除slow指针的后一个值,即删除了链表第n个位置的值,再考虑一些特殊情况,比如链表只有一个值时,可让slow->next = slow->next->next,删除之后,这时链表为空。
代码实现
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
int i=0;
struct ListNode* slow,* fast = head;
slow = (struct ListNode*)malloc(sizeof(struct ListNode));
slow->next = head;
while(i < n)
{
fast = fast -> next;
i++;
}
while(fast != NULL)
{
fast = fast -> next;
slow = slow -> next;
}
if(slow -> next == head)
return head -> next;
else
slow->next = slow->next ->next;
return head;
}
四、环形链表II(LeetCode142题)
解题思路
- 有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环。
- 如何判断一个链表是否存在环?设定两个指针slow,fast,均从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
- 如果链表存在环,如果找到环的入口点?当fast若与slow相遇时,slow肯定没有走遍历完链表或者恰好遍历一圈。于是我们从链表头与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。
![环形链表](https://img-blog.csdnimg.cn/2019011719480488.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NoZW54aXl1ZWho,size_16,color_FFFFFF,t_70)
代码实现
class Solution {
public:
ListNode * hasCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
{
return fast;
}
}
return NULL;
}
ListNode *detectCycle(ListNode *head) {
ListNode* meet = hasCycle(head);
//如果meet为空,说明不存在环
if(meet == NULL)
{
return NULL;
}
else
{
while(1)
{
//meet从slow和fast相遇的点开始走,head从头开始走
//如果二者相遇则返回这个相遇的交点
if(meet == head)
return meet;
else
{
meet = meet->next;
head = head->next;
}
}
}
}
};
五、相交链表(LeetCode160题)
可参考博主博文:有详细的解析
LeetCode相交链表解析