1.环形链表1
思路1:哈希表
遍历所有节点,每次遍历一个节点时,判断该节点是否被访问过。
遍历所有节点,每次遍历一个节点时,判断该节点是否被访问过。
可以使用哈希表来存储所有已经访问过的节点。每次到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到我们遍历完整个链表。
思路2:快慢指针
创建两个指针,一个快指针一个慢指针,快指针一次走两步,慢指针一次走一步,如果是环形链表则两个指针会相遇,所以每走一次判断两个指针是否相等。如果不是环形链表则快指针会走到NULL。
1.1.快慢指针
看图:
代码实现:
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; }
2.环形链表2
思路1:快慢指针
先上结论:下面是一个环形链表,node结点位是快慢指针相遇的位置结点,phead是入环结点。
其中L的长度等于M的长度,知道这个结论后代码就信手拈来了。
下面是证明L=M:
如果是环形链表那么两个指针会相遇,找到相遇的节点node:
那么如图设置:head到入环的结点的长度为L,入环到相遇的结点node的长度为N,环的长度为C:
那么开始遍历链表,当然慢指针slow入环时快指针已经在环里走了至少一圈,假设为x圈,
当快慢指针相遇时,慢指针在环里面走的长度就是N,因为快指针的相对于慢指针的速度为1,所以每走一步快指针就与慢指针的距离-1,直到相遇。
此时
快指针走的路程:L+N+x*C
慢指针走的路程:L+N
因为快指针的速度是慢指针的两倍,所以路程也是慢指针的两倍。
所以:
L+N+x*C=2*(L+N)
整理一下:
L=x*C-N
处理:
L=(x-1)*C+C-N
式中当x取最小值时:L=C-N
而黑色部分长度就是C-N
此时让head遍历链表,node也开始往下走,当x取的值不是1时,node结点会一直在环里遍历,最终head和node一定会在入环结点相遇。
2.1代码
struct ListNode *detectCycle(struct ListNode *head) { struct ListNode *slow=head; struct ListNode *fast=head; struct ListNode *node=head; while(fast&&fast->next) { fast=fast->next->next; slow=slow->next; if(fast==fast) break; } if(fast==NULL||fast->next==NULL) return NULL; while(fast!=node) { fast=fast->next; node=node->next; } return fast; }