快慢指针的原理
快慢指针是利用两个指针移动速度的不一样,实现一些有趣的追击行为。就像上学时求解的那些操场上的追击问题一样。
问题1:判断两个链表是否相交。(链表不存在环结构)
形如:
方法:循环第一个链表到最后一个节点,记下该节点的指针P1,然后循环第二个链表到最后一个节点,然后将这个节点的指针和P1做比较,如果相同则相交,否则就不相交。
问题2:判断两个链表是否相交。(链表可能存在环结构)
形如:
方法:先使用快慢指针遍历链表判断链表是否带环。
1、如果都不带环,则判断最后的节点指针是否相同,相同就说明相交,不相同就不相交。
2、一个带环一个不带环,则两个链表必然不相交。
3、两个都带环,则判断其中一个链表的快慢指针相遇的节点是否在另外一个链表上,在说明相交,不在说明不相交。
问题3:一个单链表,判断是否存在环
方法:采用“快慢指针”的方法。设置两个指针fast和slow,开始的时候两个指针指向链表头head,然后每次操作slow向前走一步(slow=slow->next),fast每次向前走两步(fast=fast->next->next)。
由于fast比slow快,如果有环,则fast一定先进入环,slow后进入环。然后在环内它们必然在一定步骤必然相遇。如果没有环,那么fast就会遇到null。
if (slow != null && fast->next != null)
{slow = slow->next;fast = fast->next->next;if (slow == fast)// 有环
}
else
{// 无环
}
问题4:一个存在环的单链表,找出环的入口点
分析一下:当slow刚到达环的入口处时,fast在环上的任意一个点处,此时fast距离slow设为x,x一定是小于等于环的长度r的。那么当slow再走x步后,fast必然就和slow相遇了(刚开始fast相距slow为x,slow又走了x,此时fast就走了2*x,则刚好遇上)。如上图所示。
从上面的分析知道,当fast和slow相遇时,slow走的距离x是小于等于r的,现在假设:fast已经在环内循环了n(1 <= n)圈。slow走了s步,fast就走了2*s步,由于fast走过的步数 = s + n*r。
则有下面的等式:
如果整个链表的长度是L,入口和相遇点距离是x,起点到入口点的距离是a,则有:
由(2)推出。
由环的长度=链表总长度-起点到入口的距离求出。
分析等式(5), 是相遇点到入口的距离,再结合上图分析可知,当两个指针一个指针在链表头另一个在相遇点同时出发,每次走一步,当指向头指针的走到入口处时,相遇点的指针也刚好走到入口处。
代码如下:
Node* findLoopStart(Node *head)
{Node *fast, *slow;slow = fast = head;while (slow != NULL && fast->next != NULL){slow = slow->next;fast = fast->next->next;if (slow == fast) break;}if (slow == NULL || fast->next == NULL) return NULL; //没有环,返回NULL值Node * ptr1 = head; //链表开始点Node * ptr2 = slow; //相遇点while (ptr1 != ptr2){ptr1 = ptr1->next;ptr2 = ptr2->next;}return ptr1; //找到入口点
}
扩展问题:
1、寻找链表的中点位置
2、寻找链表的倒数第k的位置