LeetCode: Linked List Cycle I && II

I

第一问很简单,就是快慢指针的一种应用。如果链表中存在环,那么快指针必然能够在某个节点上面追上慢指针,于是答案代码如下:

:::C++
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode *fast = head, *slow = head;
        while (fast != nullptr && slow != nullptr) {
            slow = slow->next;
            if (fast->next != nullptr) {
                fast = fast->next->next;
            } else {
                break;
            }
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }
};

II

第二问要求出链表开始成环的那个节点,从字面意思推测也能猜出这题既然这么出,必然是有某种规律的,因此它实际上就是第一个问题的细化了。假设从头结点到开始成环的第一个节点间长度为x,环的总长度为c,从成环节点到快慢指针相遇节点的距离为m;快指针在相遇的时候绕环A圈,慢指针绕环B圈,由于快指针的速度是慢指针的2倍,因此有关系式:

$$A*c+x+m=2*(B*c+x+m)$$


$$x+m=(A-2B)*c$$

综上我们得出结论,xm是互补的——当快慢指针在m位置相遇后,再往前走x步即可达到环的起始位置。所以此时问题就转化为,在m位置相遇后,我们如何精确地走出这x步呢?这时我们需要注意到这样一个性质:按照x的定义,如果从起始位置出发,经x步能够走到环的起始位置;而从m位置开始,经同样步数也能够走到相同位置也就是环的起始位置。因此,我们只需要设置两个指针,一个从链表开头走,一个从相遇位置继续走,两者就一定会在环的起始位置相遇。最终代码如下:

:::C++
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *fast = head, *slow = head, *meet = nullptr;
        while (fast != nullptr && slow != nullptr) {
            slow = slow->next;
            if (fast->next != nullptr) {
                fast = fast->next->next;
            } else {
                return nullptr;
            }
            if (fast == slow) {
                meet = fast;
                break;
            }
        }
        if (meet == nullptr) {
            return nullptr;
        }
        slow = head; fast = meet;
        while (slow != fast) {
            slow = slow->next;
            fast = fast->next;
        }
        return slow;
    }
};
comments powered by Disqus
Published:
2016-05-22
分类:
Tag: