Given a linked list, determine if it has a cycle in it.
Can you solve it without using extra space?
每个节点再开辟一个属性存放是否访问过,这样遍历一遍即可知道是否有环。
但为了不增加额外的空间,
可以设置两个指针,一个一次走一步,另一个一次走两步,如果有环则两个指针一定会再次相遇,反之则不会。
C++:
1 class Solution { 2 public: 3 bool hasCycle(ListNode *head) { 4 if(head==NULL||head->next==NULL) return 0; 5 6 ListNode *p=head; 7 ListNode *q=head; 8 int flag=0; 9 while(p->next) 10 { 11 if(p->next==q) 12 { 13 flag=1; 14 break; 15 } 16 p=p->next; 17 if(p->next==NULL) 18 break; 19 p=p->next; 20 q=q->next; 21 } 22 if(flag==1) 23 return 1; 24 else 25 return 0; 26 } 27 };
Python:
1 # Definition for singly-linked list. 2 # class ListNode: 3 # def __init__(self, x): 4 # self.val = x 5 # self.next = None 6 7 class Solution: 8 # @param head, a ListNode 9 # @return a boolean 10 def hasCycle(self, head): 11 if head is None: 12 return False 13 p1=head 14 p2=head 15 while True: 16 if p1.next is not None: 17 p1=p1.next.next 18 p2=p2.next 19 if p1 is None or p2 is None: 20 return False 21 elif p1==p2: 22 return True 23 else: 24 return False 25 return False
II:
Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.
Follow up:
Can you solve it without using extra space?
当fast与slow相遇时,
slow肯定没有遍历完链表,而fast已经在环内循环了$n$圈($1 \leq n$)。假设slow走了$s$步,则fast走了$2s$步(fast步数还等于$s$加上在环上多转的$n$圈),设环长为$r$,则:
设整个链表长$L$,环入口点与相遇点距离为$a$,起点到环入口点的距离为$x$,则
$L – x – a$为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于$n-1$圈内环+相遇点到环入口点,
于是我们可以从{head}开始另设一个指针{slow2},两个慢指针每次前进一步,它俩一定会在环入口点相遇。
分析来自 ACM之家。
1 class Solution { 2 public: 3 ListNode *detectCycle(ListNode *head) { 4 if(head==NULL||head->next==NULL) return NULL; 5 ListNode *p=head; 6 ListNode *q=head; 7 while(p->next&&p->next->next) 8 { 9 q=q->next; 10 p=p->next->next; 11 if(q==p) 12 { 13 q=head; 14 while(q!=p) 15 { 16 p=p->next; 17 q=q->next; 18 } 19 20 return q; 21 } 22 } 23 24 return NULL; 25 } 26 };