您的位置:首页 > 其它

[LeetCode] Linked List Cycle 与 Linked List Cycle II

2016-03-07 14:37 344 查看

前言

Linked List Cycle 与 Linked List Cycle II是LeetCode链表系列很经典的两道题,值得研究一下。

题目

https://leetcode.com/problems/linked-list-cycle/

https://leetcode.com/problems/linked-list-cycle-ii/

Linked List Cycle

Given a linked list, determine if it has a cycle in it.

Can you solve it without using extra space?

分析

判断链表有没有环,最容易想到的方法是,用一个哈希表来记录每个元素是否被访问过,一旦出现某个元素被重复访问,说明存在环。空间复杂度 O(n),时间复杂度 O(N)。

最好的方法是时间复杂度 O(n),空间复杂度 O(1) 的。我们可以设置两个指针,一个快一个慢,快

的指针每次走两步,慢的指针每次走一步,如果快指针和慢指针相遇,则说明有环。

关于这种“快慢指针法”,还可参看LeetCode官方博客文章:http://articles.leetcode.com/detecting-loop-in-singly-linked-list

另外,对于这种解法的正确性,即“快慢指针若相遇链表保证有环”的正确性,这里引用一个这篇博客文章提到的证明方法:



如图,在任意时刻,p1和p2都在环上。由于p1每次向前1步,p2每次向前两步,用相对运动的观点(中学物理)来看,把p1看作静止,那么p2每次相对p1向前1步,二者在顺时针方向上的距离每经过一个时刻就减少1,直到变为0,也即二者恰好相遇。这样就证明了对于有环链表,二者也是必然在某一时刻相遇在某个节点上的。(除非这个环有无穷大,那么p2追上p1可能需要t=∞的时间)

代码

/**
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode * SlowPtr = head, *FastPtr = head;
while (FastPtr != NULL && FastPtr->next != NULL) {
SlowPtr = SlowPtr->next;
FastPtr = FastPtr->next->next;//快指针每次走两步
if (SlowPtr == FastPtr)
return true;
}
return false;
}
};


Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Note: Do not modify the linked list.

Follow up: Can you solve it without using extra space?

分析

题意很简单,如果有环,返回环的入口,如果没有,则返回NULL。

对于有环的链表而言,当 fast 与 slow 相遇时, slow 肯定没有遍历完链表,而 fast 已经在环内循环了 n 圈 (1 ≤ n)。现在假

设 slow 走了 s 步,则 fast 走了 2s 步( 同时,fast 步数还等于 s 加上在环上多转的 n 圈),设环长为 r,则有:

2s = s + nr

因此,

s = nr

设整个链表长 L,环入口点与相遇点距离为 a,起点到环入口点的距离为 x,则

x + a = nr = (n–1)r + r = (n − 1)r + L − x

x = (n − 1)r + (L–x–a)

L–x–a 为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于 n − 1 圈内环 + 相遇

点到环入口点,于是我们可以从 head 开始另设一个指针 slow2,两个慢指针每次前进一步,它俩一定会在环入口点相遇。

另外,刚才那篇文章最后也讨论了这个找环入口的问题,解释地相当清楚明了,一并推荐之。

代码

class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode * SlowPtr = head, *FastPtr = head;
while (FastPtr != NULL && FastPtr->next != NULL) {
SlowPtr = SlowPtr->next;
FastPtr = FastPtr->next->next;
if (SlowPtr == FastPtr) {//存在环
ListNode *WalkerPtr = head;//重新设置一个慢指针
while (WalkerPtr != SlowPtr) {
WalkerPtr = WalkerPtr->next;
SlowPtr = SlowPtr->next;//直到两个慢指针相遇
}
return WalkerPtr;
}
}
return NULL;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode 链表