带环链表2

lintcode 带环链表2

描述

给定一个链表,如果链表中存在环,则返回到链表中环的起始节点,如果没有环,返回null。

样例

给出-21->10->4->5,返回10
解释:
最后一个节点5指向下标为1的节点,也就是10,所以环的入口为10

挑战

不使用额外的空间

思路

和带环链表找环一样,使用快慢指针,当fast == slow的时候,就说明有环了。此时通过数学计算可以证明此时slow指针走的步数等于环的长度。证明如下:
设slow指针走了i,则fast走了2i,再设环外长度为m,环长为n,则有如下的等式
(i-m)≡(2i-m)(mod n)
第一次相遇时(不包括第一次在head处)i-m=n-m,2i-m=2n-m,可以得到i = n.
也就是说,此时在环内已经走了n-m的长度,剩下m的长度。于是此时可以让slow从head处开始走,fast的步长变为1,再继续走,再次相遇时,就是环的入口。

代码

/**
 * Definition of singly-linked-list:
 * class ListNode {
 * public:
 *     int val;
 *     ListNode *next;
 *     ListNode(int val) {
 *        this->val = val;
 *        this->next = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param head: The first node of linked list.
     * @return: The node where the cycle begins. if there is no cycle, return null
     */
    ListNode * detectCycle(ListNode * head) {
        // write your code here
        if (!head || !head->next) return false;
        ListNode *fast = head->next->next, *slow = head->next;
        int index;
        while (fast && fast->next) {
            if (fast == slow) {
                slow = head;
                while (slow != fast) {
                    slow = slow->next;
                    fast = fast->next;
                }
                return fast;
            }
            fast = fast->next->next;
            slow = slow->next;
            index++;
        }
        return NULL;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_40147449/article/details/87560928