141. Linked List Cycle
Given a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space?
判断一个链表有没有成环。
不使用额外的空间来完成,很自然地就想到使用快慢指针来求解。两指针同时起步,慢指针每走一步快指针就走两步,当它们再次相遇即证明链表成环。这道属于easy题,直接看代码:
class Solution {
public:
bool hasCycle(ListNode *head) {
if (!head) return false;
ListNode *fast = head, *slow = head;
while (fast->next && fast->next->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return true;
}
}
return false;
}
};
时间复杂度O(n):假如没有环,快指针到达链表尾就结束,runtime取决于链表长;如果有环,当快慢指针第二次相遇时,快指针比慢指针多跑了一圈,由于快指针步长比慢指针快1,所以上面代码while循环次数=环的长度。
空间复杂度O(1)。
在官方solution中还看到一种使用hash table的方法。把结点逐个检查并存入hash table,如果结点已经在hash table中就证明有环。这种方法比较直观,但缺点是空间复杂度是O(n)。
142. Linked List Cycle II
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
在上一题的基础上,如果有环就找出环的入口结点。
主要思想和上一题一样也是用快慢指针先找到相遇结点。比如有链表:
1-2-3-4-5
| |
7 - 6
快慢指针相遇在结点6,求环的入口就相当于求:
链表L1 1-2-3-4-5-6-7-3-4-5-6 和
链表L2 1-2-3-4-5-6 尾对齐时的交集首结点。(类似LeetCode 160. Intersection of Two Linked Lists)
两链表的长度差=环长=快慢指针相遇时所走步数(上题的while循环次数)
fast
|
1-2-3-4-5-6-7-3-4-5-6
1-2-3-4-5-6
|
slow
在快慢指针相遇后,让慢指针重新指向首结点,然后快慢指针同时以步长1向前移动,当下一次他们再次相遇时,该处结点即为环入口,如上图结点3。
数学推导见:http://www.jianshu.com/p/ce7f035daf74 或者LeetCode本题Discuss
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
}
ListNode *detectCycle(ListNode *head) {
if (!head) return NULL;
ListNode *fast = head, *slow = head;
while (fast->next && fast->next->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow) {
slow = head;
while (fast!=slow) {
fast = fast->next;
slow = slow->next;
}
return fast;
}
}
return NULL;
}
};