题目描述
题目分析:
之前我们遇到的都是很纯粹的单链表题目,今天这道题涉及到了链表带环问题,链表带环问题也很容易理解,就是尾节点的next并不等于空指针,而是指向了该链表当中的某一个节点,就形成了闭环,而链表带环导致最大的问题就是无法直接遍历整个链表(不知道结束标志)
思路:定义快慢指针,快指针每次走两步,满指针每次走一步,若快指针和慢指针相遇了,则带环,若快指针已经走到了空或者尾还没有和慢指针相遇,说明不带环
这个思路应该不难理解,因为不带环的话,就是一个纯粹的单链表,快慢指针同时走,快指针走的快,必然先走完链表,慢指针不可能追赶上
思考点1:为什么带环时,快指针走两步,慢指针走一步,就一定能相遇?
假设慢指针入环时和慢指针相距L(下面是一个链表的抽象图)
快指针每次走两步,慢指针每次走一步,因此他们之间的距离每次缩小1步,所以距离变化就是
L , L-1, L-2, ············2, 1, 0 ,因此距离一定会经过减为0的过程,因此一定能相遇
思考点2.若慢指针每次走一步,而快指针每次走N(N>2)步,那么快慢指针也一定能够相遇吗?
假设快指针每次走3步,慢指针每次走1步,会是什么情况呢?
快指针走3步,慢指针走1步,因此差距每次缩小2步,那么快慢指针距离变化过程为 L-2,L-4, L-6·······,此时要分L是奇数还是偶数:
若L为偶数:L-2, L-4, L-6····· 4, 2, 0,会经过为相距为0的时刻,也就是可以相遇
若L为奇数:L-2, L-4, L-6····· 5, 3, 1, -1,会跳过相距为0的时刻,此轮无法相遇,进入下一轮追击。开始相距C-1, 若C-1为偶数,则该轮可以相遇,若C-1为奇数,则还会跳过距离为0的时刻,永远无法相遇
这就是为什么我们要让快指针每次走两步,慢指针每次走一步的原因
完整代码
bool hasCycle(struct ListNode *head) {
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
return true;
}
return false;
}