码迷,mamicode.com
首页 > 编程语言 > 详细

Floyd判圈算法

时间:2015-06-17 09:37:04      阅读:249      评论:0      收藏:0      [点我收藏+]

标签:算法   leetcode   指针   链表   回路   

最近在刷LeetCode,遇到一个判断链表中是否有回路的题,也算是一道经典题目了。今天和大家分享一下解题方法。

题目:

检查链表是否有回路。如果有回路,则返回回路的起始节点;如果没有,则返回null。要求不能使用额外的存储空间记录链表节点的内容。

分析:

基本思路还是使用Floyd判圈算法。指针hare每次向后移动2个节点,指针tortoise每次向后移动1个节点。如果hare最终指向尾节点则该链表无回路。否则,该链表有回路。(详见《LeetCode #141 Linked List Cycle》)

现在我们已经知道了链表有没有回路,但是如何在不使用额外空间并且不修改原链表的基础上获得回路的起始节点呢?这需要一些数学推导:

设链表起始节点为H,回路起始节点为S,两指针第一次相遇节点为M。
回路的长度为c,S到M的距离为c1,M到S的距离为c2。
设H到S的距离为d。
hare每次移动2,tortoise每次移动1。移动k次后两者相遇。不难发现,H到M的距离为k。

为了便于理解,请参考下图:

技术分享

由已知条件,可得到下列等式:

hare和tortoise相遇时,hare套了tortoise若干圈。则有:

2k – k = nc = k,n为正整数。

从上图中定义的距离关系,可以得到

c = c1 + c2
k = d + c1

由以上格式变换可得: d = nc – c1 = c2 + (n-1)c

该式具有什么重要意义呢?假设2个指针分别从H和M出发,都是每次移动1的距离,他们会在哪里相遇?

一个指针从H出发移动d后到达M。另一指针移动 c2 + (n-1)c,(n-1)c意味着绕了n-1圈又回到M,实际上相当于走了c2的距离,到达M。我们发现,两指针必然在S相遇

此时两指针相遇的节点即是回路的起始节点。

 

代码:

C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct ListNode *detectCycle(struct ListNode *head) {
    if (head == NULL) return 0;
    struct ListNode *hare = head;
    struct ListNode *tortoise = head;
    while (hare->next != NULL && hare->next->next != NULL){
        hare = hare->next->next;
        tortoise = tortoise->next;
        if (hare == tortoise) {
            hare = head;
            while (hare != tortoise){
                hare = hare->next;
                tortoise = tortoise->next;
            }
            return hare;
        }
    }
    return NULL;
}

 

注:原文见我的博客《LeetCode #142 Linked List Cycle II

Floyd判圈算法

标签:算法   leetcode   指针   链表   回路   

原文地址:http://blog.csdn.net/u014076884/article/details/46528733

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!