链表环检测算法

来源:互联网 发布:遗传身高计算法 编辑:程序博客网 时间:2024/06/06 17:33

给定两个LeetCode上的问题

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?

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.

1.如何判断一个链表是否有环
2.如果一个链表有环,找出这个环的开始节点

环检测(Cycle detection)

对于链表环检测问题可以使用”龟兔赛跑”算法来进行判断:即使用两个指针,一个指针为快指针(兔)一次移动两步,而另一个指针为慢指针(龟)一次移动一步。如果这个链表有环的话,那么这两个指针一定会在环上的某一点相遇。
cycle
首先定义一些变量,如图
令 m为链表开始点到环开始点的节点数, 假设龟和兔在离环开始k个节点的地方相遇。环的节点数为n.

为什么这个算法是正确的?

假设龟走了i步之后再相遇点相遇,此时兔子走了2i步,并且假设乌龟在环上已经走了p圈,而兔子走了q圈。那么有:

2i = m + q*n + k
i = m + p*n + k


2*(m + p*n +k) = m + q*n + k
⇒ m + k = (q-2p)n

显然,至少存在一组值q, p, k使得该等式成立。证明(略)

如何找到环的开始点?

当乌龟和兔子在相遇点相遇之后,此时将乌龟放到链表的开始节点,保持兔子在相遇点。如果此时以相同的速度移动乌龟和兔子,那么乌龟和兔子的第一次相遇肯定是在环的开始节点。

如果让乌龟和兔子一起移动m+k步,那么此时乌龟已经移动到了他们原来的相遇点(meeting point)。又因为 m+k = (q-2p)n 。 因此,兔子已经在环上走了(p-2p) 圈。 (注意:这次移动兔子的起点是在相遇点,乌龟的起点是在链表开始(头)节点上,并且他们的移动速度是一样的)。
此时,如果乌龟移动的是m步而不是m+k步,那么乌龟到达了环的开始节点上。而兔子还差k步就完成了在环上走q-2p圈,即此时,兔子也在环的开始节点上。

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?

bool hasCycle(ListNode *head) {    if(!head)  return false;    ListNode* faster = head;    ListNode* slower = head;    while(faster->next != NULL && faster->next->next != NULL) {        faster = faster->next->next;    //快指针一次移动两步        slower = slower->next;  //慢指针一次移动一步        if (faster == slower)            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.

ListNode *detectCycle(ListNode *head){    if(!head)  return NULL;    ListNode *faster=head;    ListNode *slower=head;    bool flag = false;    while(faster->next != NULL && faster->next->next != NULL)    {        faster = faster->next->next;        slower = slower->next;        if (faster == slower) {            flag = true;            break;        }    }    if (flag) {        slower = head;        while(slower != faster) {            slower = slower->next;            faster = faster->next;        }        return slower;    }    return NULL;}
1 0
原创粉丝点击