关于循环单链表的两题,先来简单的。
Given a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space?
判断是否为循环链表。
利用循环链表的周期性,两个步长不一样的指针一定会有相遇的点,而如果无环的话,步长大的一定会先行结束。
1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Solution { 10 public: 11 bool hasCycle(ListNode *head) { 12 if (head == NULL) 13 return false; 14 ListNode *p1 = head, *p2 = head; 15 while (p1 != NULL && p2 != NULL && p2->next != NULL) { 16 p1 = p1->next; 17 p2 = p2->next->next; 18 if (p1 == p2) 19 break; 20 } 21 22 if (p1 == NULL || p2 == NULL || p2->next == NULL) { 23 return false; 24 } 25 26 return true; 27 } 28 };
问题进阶
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?
这是要找出环的起点。
先看看以上的结果,我们设从链表头到环起点的距离为t0,快慢指针相遇的点到环起点的距离为t1,快慢指针在环中走过的周期数分别为N1,N2,周期长度T
快指针路程T1 = t0 + t1 + N1*T
慢指针路程T2 = t0 + t1 + N2*T
快慢指针路程关系是T1=2*T2
结合以上式子,就得到t0 = (N1-2*N2)*T - t1
以上式子说明了什么?我们可以想象下当慢指针在相遇后继续前进t0步,那就是刚好到了环的起点了!
那怎么约束只走t0步呢?只需要再找一个指针,跟慢指针一样,每次一步,到环的起点的步数也是t0!
即两指针相遇时点就一定是环的起点了~上代码:
1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Solution { 10 public: 11 ListNode *detectCycle(ListNode *head) { 12 if (head == NULL) 13 return NULL; 14 ListNode *p1 = head, *p2 = head; 15 while (p1 != NULL && p2 != NULL && p2->next != NULL) { 16 p1 = p1->next; 17 p2 = p2->next->next; 18 if (p1 == p2) 19 break; 20 } 21 22 if (p1 == NULL || p2 == NULL || p2->next == NULL) { 23 return NULL; 24 } 25 p2 = head; 26 while (p1 != p2) { 27 p1 = p1->next; 28 p2 = p2->next; 29 } 30 return p1; 31 } 32 };