判断单链表中是否有环?如果有起点在哪里?环长度?

需求:

        判断一个单链表是否有环?如果有换找出环的起点,以及环的长度。

分析:

        1)定义两个指针p1和p2,p1每次走1步,p2每次走两步,如果单链表有环则p1和p2一定会相遇;为什么一定有环一定会相遇?我们先定义一些变量:假设有环,环长为n,然后设 链表的起点环起点 的长度为a,p1到环的起点时p2位于环的位置为x(0<=x<n)。

        现在到这里就很容易的理解为什么一定会相遇,因为当p1到环的起点时,p2位于环的位置(距离环起点的顺时针位置)为x,那么p2与p1相差n-x步,而且p2每次总比p1块一步,所以一定会追上p1。

        2)设p2和p1第一次相遇的点位于环的位(置距离环起点的顺时针位置)为b,此时

            p1走的距离:a+b

           p2走的距离:p2速度是p1的二倍所以 2*(a+b),但是因为p1和p2相遇所以p2走的距离也是 a+b+n*k,即2*(a+b) == a+b+n*k,两边消去一个(a+b)

            所以推导出  a+b == n*k

        3)如何找环的起点,第一次相遇之后,把指针p1拉回到链表的起点,然后把p2的速度改为每次走一步即和p1速度相同,p2把第一次相遇点作为起点,那么当p1和p2再次相遇的点就是圈的起点,因为第二次相遇时p1刚好走a步到环的起点,p2刚好走b+a步,由于b+a == n*k刚好也在环的起点。

        

代码:

ListNode *detectCycle(ListNode *head) {
    ListNode *p1 = head, *p2 = head;
    do{
        if((p2 == 0) || (p2->next == 0)) {      //链表是有限长度的,已经走到链表尾部了,说明没有环
            return 0;
        }

        p2 = p2->next->next;         //p2一次走两步
        p1 = p1->next;//p1一次走一步
    }while(p1 != p2)

        for(p1 = head; p1 != p2; p1 = p1->next, p2 = p2->next);  //p1拉回起点,p2从相遇点开始走都是每次直走一步直到再次相遇p1就是起                                                                 //点
        return p1;
}


发布了38 篇原创文章 · 获赞 43 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_40272386/article/details/80552266