题目
给你一个链表的头节点head,判断链表中是否有环。如果链表中存在环,则返回true;否则,返回false。
题解
使用快慢指针法。定义一个慢指针slow和一个快指针fast,slow每次走一步,fast每次走两步,直到fast为空或者fast->next为空为止。如果链表中存在环,则在某一时刻fast一定会追上slow。所以在循环过程中,如果slow和fast相等则链表中存在环;如果直到循环结束slow和fast都不等则链表中不存在环。
代码如下:
bool hasCycle(struct ListNode* head) { struct ListNode* slow = head; struct ListNode* fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) return true; } return false; }
思考:为什么slow走1步,fast走2步时,slow和fast一定会相遇呢?如果slow走1步,fast走3步,slow和fast一定会相遇吗?
第一个问题,如果链表有环,slow走1步,fast走2步时,fast比slow先进环。假设当slow进环时,fast与slow的距离为N。slow进环后,fast开始追赶slow,slow每走1步、fast每走2步,slow和fast之间的距离减少1步。在整个追赶过程中,slow和fast之间的距离变化为:N、N-1、N-2、……3、2、1、0,所以slow和fast一定会相遇。
第二个问题,如果链表有环,slow走1步,fast走3步时,fast比slow先进环。假设当slow进环时,fast与slow的距离为N。slow进环后,fast开始追赶slow,slow每走1步、fast每走3步,fast和slow之间的距离减少2步。在整个追赶过程中,当N为偶数时,slow和fast之间的距离变化为:N、N-2、N-4、……4、2、0,slow和fast一定会相遇;当N为奇数时,fast和slow之间的距离变化为:N、N-2、N-4……3、1、-1,此时fast开始新一轮的追赶。假设环的长度为C,此时fast与slow的距离为C-1,如果C-1为偶数,slow和fast一定会相遇;如果C-1为奇数,slow和fast永远不会相遇。所以slow走1步,fast走3步时,slow和fast不一定会相遇。