题目描述
题目要求
判断一个单链表是不是环形链表,是就返回true 不是就返回false
思路
- 要搞清楚环形链表长啥样
- 环形链表有哪些特征
环形链表顾名思义就是在链表中有一个类似环形的结构, 它和普通单链表的区别就是 你用遍历普通单链表的法子遍历一个环形链表的话 会陷入死循环(因为环形链表没有一个节点指向NULL),而这恰好就是环形链表区别于普通链表的特征,我们以此为突破口
我们如何利用环形链表的这个特征呢?
我们要利用这个特征就是要看 在遍历这个链表的时候是不是陷入了循环里面。
怎么做呢?
答:快慢指针
为啥要用快慢指针呢?
答:
你遍历环形链表,当你的指针进入环后,它就出不来了,一直在环里转,
我们说过这是环形链表的特征。
我们把一个指针假设为一个人(小明)
我们在引入另一个指针(假设它叫小红),小红比小明跑的快。
当他们两个人同时从起点(头节点
)出发后,小红跑在了前面(因为小红的速度快),小红就先进循环,小明就后进循环,但这个循环是死循环呀,他们永远也出不来,所以他们会在循环里一直跑,但小红的速度快呀,小红可能跑完一次循环后追上小明(意思就是小红要超小明一圈了,就和学校运动会跑3000米一样,跑的快的同学可能会追上最后的那名同学,超他一圈的距离),这个时候(就是小红要超过小明的时候)有小红这个指针等于小明这个指针
有这个特征就可以判断这是个环形链表了,因为如果是直的链表,由于小红的速度快,小红会永远跑在小明的前面,就不存在他们两相等的情况。
所以:
一个快指针fast
一个慢指针 slow
慢指针一次遍历一个节点,快指针可以一次遍历2个节点
我们可以写下这样的代码:
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(slow == fast)
return true;
}
return false;
}
注意了哈
有朋友会问 为什么慢指针slow
要走1步,而快指针fast
要走2步
这个问题有点复杂
有规律得出,如果那个环里的节点是偶数个的话 那么只要fast比slow快就行,fast可以走3步,4步 都行
如果那个环里的节点数是奇数的话,那么fast如果不是走的2步就有可能直接跳过slow了(错过了,就比如fast还有一个节点就追上slow了,但由于fast一次走3个节点,他就直接跳过slow,指向了后面的节点了)