Quantcast
Channel: xdlove
Viewing all articles
Browse latest Browse all 4

Floyd判圈算法

$
0
0

一、链表判环

如何判断一个简单的单向链表是否有环,我们只需要维护两个指针pSlow,pFast,一开始初始化为链表头指针,pSlow每步前进一个节点,pFast每步前进两个节点。如果链表有环,则pSlow和pFast肯定会相遇。

二、求环的起点与环长

求环的长度简单,因为我们已经知道两个指针的相遇地点一定是在环内,那么通过pSlow走了环一圈后,其实pFast已经走了两圈,且这两个指针会再次相遇。测试pSlow走了步长为环的长度。

求环的起点有点复杂,首先我们先把问题抽象为数学问题。我们设链表头结点pHead与环的起点距离为L个节点(不包括环的头结点,但是包含链表头结点,以下谈及的距离都是如此),环的头结点离节点P(pSlow与pFast相遇的节点)距离为S个节点节点P离环的头结点距离为Y个点,我们假设pSlow走了T个时间单位,则pFast走了2T;环的长度为C;

则有这样几个方程:

2T = T + N1C            ——->   T = N1C                            ®1

2T = L + S + N2C     ——->   (2N1 – N2)C = L + S      ®2

N3 = 2*N1 – N2         ——->   N3C = L + S                    ®3

C = S + Y                     ——->   (N3 – 1)C + Y = L           ®4

由®4知,当pResult从pHead节点走到P节点时(即走了L距离),pFast从P节点同时出发,一定会在环的起点与pResult相遇,因为N3已知,整个方程一定有解的。记住此时,两个指针每步走一个节点。

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *pSlow = head, *pFast = head;
        bool flag = false;
        while (pFast != nullptr && pFast->next != nullptr) {
            pFast = pFast->next->next;
            pSlow = pSlow->next;
            if (pFast == pSlow) {
                flag = true;
                break;
            }
        }
        ListNode *Result = head;
        if (flag) {
            while (Result != pFast) {
                Result = Result->next;
                pFast = pFast->next;
            }
        }
        return flag == true ? Result : nullptr;
    }
};

 

 

 


Viewing all articles
Browse latest Browse all 4