LeetCode Linked List Cycle & Linked List Cycle II题解

来源:互联网 发布:国家大数据综合试验区 编辑:程序博客网 时间:2024/06/06 01:18
  • Linked List Cycle

 

        Given a linked list, determine if it has a cycle in it.Follow up:Can you solve it without using extra space?

        题目的意思就是在利用O(1)的空间判断一个链表是否存在环。我一开始的想法就是,每访问 一个节点,就遍历这个节点前面的所有节点,然后判断是否相同,如果相同就说明有环。如果所有的节点都访问完了还是没有发现有节点相同,则说明该链表没有环。但是这个想法很快被毙掉,因为这个算法的复杂度将会达到O(N^2),实在太慢!后来又想到了利用两个指针,一快一慢,如果有环,则这两个指针一定会相遇。这个方法不需要额外的空间,同时复杂度是O(N)的。非常符合这道题目的要求。具体来说,就是设立两个指针,一个fast,一个slow。fast在每一个step中移动两步,slow每次移动一步。如果两者相遇,必然是存在环,同时fast将slow套圈了才会出现这种情况。这道题目也就迎刃而解了,具体的实现代码如下。

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

  • Linked List Cycle II

        Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull. Follow up:Can you solve it without using extra space?

        Linked List Cycle II 不仅要求判断是否存在环,同时还需要在存在环的情况下找出环的起始节点。这就比I要难一些。最开始我想到的方法还是跟上题类似,一个fast ,每次移动两步,一个slow,每次移动一步。两个指针不仅要向前移动,同时还需要记录各自走的步数(fastCount和slowCount)。当相遇的时候,fastCount减去slowCount就是换的长度(假设这个长度的len)。这个时候让fast和slow重新指向head节点。然后先让fast指针向前移动len步。之后fast和slow再同时移动,两个每次均移动一步。当两者相遇的时候就是环的其实节点。具体代码如下:

class Solution {public:    ListNode *detectCycle(ListNode *head) {        if(!head || !head->next)            return NULL;        ListNode *fast,*slow;        int fastCount = 1,slowCount = 1;        bool hasCycle = false, flag = false;        fast = slow = head;        while(fast)        {            fast = fast->next;            ++fastCount;            if(flag)            {                slow = slow->next;                ++slowCount;                flag = false;            }            else            {                flag = true;            }            if(fast == slow)            {                hasCycle = true;                break;            }                    }                if(!hasCycle)            return NULL;        int cycleLen = fastCount - slowCount;                fast = slow = head;        for(int i = 0; i < cycleLen; ++i)            fast = fast->next;        while(true)        {            if(fast == slow)                return slow;            fast = fast->next;            slow = slow->next;        }    }};

        但是在参考了他人的算法之后,发现这个算法可以更加精简。先来看下面这个图。

       

          p1为环开始的节点,p2为fast指针和slow指针相遇的节点。A 、B、 C分别为三段的距离。当相遇的时候slow指针经过的路程为(A + B)而fast指针经过的路程为(A + B + C + B)。同时fast经过的路程又是slow的两倍,所以又(A + B + C + B)= 2(A + B)所以最后得到A = C!那么当两者相遇的时候,只需要将slow指针放回到起始节点,而fast指针继续在原有位置上向前走。两个指针一相同的速度访问节点。当两者再次相遇的时候,相遇的节点就是环路起始节点p1。实现代码如下:

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



0 0
原创粉丝点击