链表找环的起点

来源:互联网 发布:mariadb与mysql的语法 编辑:程序博客网 时间:2024/05/17 22:25

牛客网
思路:
1. 先使用快慢指针确定是否有环。原理
2. (1)方法1 如果有环,计算出环的长度,采用快慢指针,定位环起点
3. (2)方法2 如果有环,设置两个指针从链表头和快慢指针相遇点逐步前进,相遇点则是链表环起点。原理
方法一:

ListNode *detectCycle(ListNode *head) {        ListNode *fast,*slow;        fast = slow = head;        while(fast&&fast->next&&fast->next->next){              slow = slow->next;              fast = fast->next->next;              if(slow == fast) break;        }        if(!fast||!fast->next||!fast->next->next) return NULL;        //寻找环的长度        ListNode *p;        int count;        p = slow;        count = 1;        while(p->next!=slow){            p = p->next;            count ++;        }        p = head;        for(int i = 0;i<count;i++)            p = p->next;        ListNode *c = head;        while(p!=c){            c = c->next;            p = p->next;        }        return c;    }

方法二:

    ListNode *detectCycle(ListNode *head) {        ListNode *fast,*slow;        fast = slow = head;        while(fast&&fast->next&&fast->next->next){              slow = slow->next;              fast = fast->next->next;              if(slow == fast) break;        }        if(!fast||!fast->next||!fast->next->next) return NULL;        //寻找环的长度        fast = head;        while(fast!=slow){            fast = fast->next;            slow = slow->next;        }        return slow;    }

分析:

  1. 为什么通过判断快慢指针是否相等可以判断环是否存在
    假设链表路径为:x + y,其中x为环之前的路径长度,y为环之后的路径长度
    慢指针追上快指针,则必然是在环中,无环只会差距越来越大。
    当快指针追上慢指针时有
    设fast: m,slow: n; (m,n分别为fast,slow指针移动的距离)

    {(mx)%y=(nx)%ym=2n

    =>[(n-x) + n]%y = (n-x) %y
    =>n是y的整数倍
    那么n是一步一步走的,则n必然可以为n的整数倍。
    则通过判断快慢指针是否相等可判断是否有环

  2. 找到相遇点如何求环的起点
    链表图
    设相遇为p,则划分环为cd 两段,c为已经走过的点,则
    x+c+k*(d+c) = 2*(x+c)
    => x = kd+(k-1)c
    => x = (k-1)(d+c) + c
    则设置两个指针一个指向链表头,一个指向相遇点,两个每次前进一步,相遇点则是环的起点

参考:链表环起点