leetcode141.环形链表

判断一个单链表有无环:
 
问题解法:
1.set缓存遍历过的节点指针,到达单链表尾部无环,set元素重复则有环。
2.使用两个指针遍历slow+fast,slow每次走一步,fast每次走两步。fast走到链表尾部无环,slow与fast重叠则有环。
 
方法2思路:
若链表的起始位置等于环的起始位置:slow走一圈回到起始位置,fast刚好走了两圈。
环的起始位置在链表的其他位置:待slow走到环的起始位置,fast在环的任意位置,可以看成是起点不同的遍历,此时slow在走一圈范围内肯定会被fast超越(起点相同情况下,slow走一圈,fast走两圈;fast起点比slow靠后,fast能在slow走一圈前超越)。fast每次移动时靠近slow一步,两者肯定会重叠。
 
代码如下:
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* slow = head;
        ListNode* fast = head;
        
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
                        
            if (fast == slow)
                return true;
        };
        
        return false;
    }
};
 
找出环的起始位置并求环的长度:
假设环的起点为a,环的长度为n,slow与fast重叠于环的位置b(单链表总长度: a+n),此时fast绕环走了k圈。
slow与fast重叠时,slow走了 (a+b) 步,fast走了(a+k*n+b)步,fast步数=slow步数*2。
即 2*(a+b) = (a+k*n+b); => k*n = a+b;
此时,再把slow移动到单链表起始位置(fast位于重叠位置b),slow与fast每次都只走一步。slow走到a位置时,fast走了(n-b) + k*n步,结合前面的公式,fast也会走到环的起始位置并与slow重叠,即环起始位置slow==fast。知道了环起始位置,只要遍历即可得到求环的长度。
 
代码如下:
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* slow = head;
        ListNode* fast = head;
        
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
            
            if (slow == fast) {
                slow = head;
                while (slow != fast) {
                    slow = slow->next;
                    fast = fast->next;
                }
                return slow;
            }
        }
        
        return nullptr;
    }
};
原文地址:https://www.cnblogs.com/hanawasakuraki/p/9392459.html