天天看点

LeetCode-Linked List Cycle II

题目:LeetCode-Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Follow up:

Can you solve it without using extra space?

解释:

做了1就忍不住要做2,这道题要求高了一点。要返回开始循环的节点,那么你肯定得找到这个节点。怎么找?循环链表中,有且只有两个节点的指针域是相同的,并且相同的两个指针就是指向循环开始的节点的,所以可以根据这一点来寻找循环链表的开始节点。

要实现这个要求,有一个比较直接的方法,即逐个比较法。就是用两个指针,一个在循环部分不断的循环(指针 fast),一个从链表的头指针开始移动(指针slow),slow每移动一次,fast 移动一圈,依次比较他们是否相同(虽然感觉这样的时间负责度会很大,但这总比不做好吧)。实现代码如下:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow, *fast;
        ListNode  *p = NULL;
        slow = fast = head;
        while()
        {
            if(fast == NULL || fast->next == NULL )
                return NULL;
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast)
            {
                p = slow;  //记录当前节点,作是否循环一圈的判断
                slow = head;
                while()
                {
                    if(slow == fast) return slow;
                    fast = fast->next;
                    if(fast == p)
                    {
                        slow = slow->next; //当fast回到P处
                        //时,即循环完了一圈,此时slow移动一位.      
                    }
                }
            }
        }

    }
};
           

运行,程序通过,不过果然,运行时间72Ms,离系统记录的12Ms还差很多,这时就要改进代码了。

再仔细观察一下循环链表的特点,发现在一个循环链表中,快慢指针相遇的点总是固定的某点,如图中的3处,因为快指针一定要比慢指针快了一圈,它们才有可能相遇。再假设它们是完全循环链表,那么它们相遇点肯定是第一个节点,那么非完全循环链表为什么不是相遇在开始的节点处呢?因为它事先跑了一段无关的路了呀(图中的1~2段),也正是因为它们跑了一段路了,所以相当于它们在3处开始移动的,也就是说明了什么?说明1~2段和2~3段的路程是相同的!!所以一个指针从链头开始,一个指针从相遇处开始,同步移动,它们必然会在循环开始处相遇,这样也就找出来题求的节点了。

LeetCode-Linked List Cycle II

代码如下:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow, *fast;
        ListNode  *p = NULL;
        slow = fast = head;
        while()
        {
            if(fast == NULL || fast->next == NULL )
                return NULL;
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast)
            {
                slow  = head;
                while()
                {
                    if(slow == fast) return slow;
                    slow = slow->next;
                    fast = fast->next;
                }
            }
        }

    }
};
           

运行用时12Ms。这是完全自己写的代码,还没看大神们的代码,不知是否相同。虽然思考这道题时用了不少时间,但看到自己的代码被access时,觉得还是值得的。