leetcode 142. Linked List Cycle II(Floyd判圈算法)

题目链接

leetcode 142. Linked List Cycle II

题目大意

给定一个链表,判断链表内部是否含有环。输出环的起始位置。不能有额外的存储空间。

思路

利用双指针,慢指针每次前进一个节点,快指针每次前进两个节点;
设从出发点到环的起点的距离为 L 1 L_1 L1,两个指针第一次相遇的位置距离环的起点为 L 2 L_2 L2,环的长度为 N N N
那么从出发点到相遇时,慢指针走过的节点数为: L 1 + L 2 + N ∗ a L_1+L_2+N*a L1+L2+Na
快指针走过的节点数为: L 1 + L 2 + N ∗ b L_1+L_2+N*b L1+L2+Nb
由于快指针速度是慢指针的两倍,那么有: L 1 + L 2 + N ∗ b = 2 ( L 1 + L 2 + N ∗ a ) L_1+L_2+N*b=2(L_1+L_2+N*a) L1+L2+Nb=2(L1+L2+Na)
化简得: L 1 + L 2 = ( b − 2 a ) ∗ N L_1+L_2=(b-2a)*N L1+L2=(b2a)N,即从出发点到两者相遇点的距离=环的长度的整数倍

此时需要求取 L 1 L_1 L1的长度,由 L 1 + L 2 = ( b − 2 a ) ∗ N L_1+L_2=(b-2a)*N L1+L2=(b2a)N==> L 1 = N − L 2 L_1=N-L_2 L1=NL2,故只需维护一个指针从出发点开始,一个指针从相遇点开始,两者的下一次相遇就是环的起始位置。

Floyd判圈算法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
     
public:
    //返回链表环开始的节点
    //不利用多余的内存空间
    //双指针,floyd判圈算法
    ListNode *detectCycle(ListNode *head) {
     
        ListNode *l=head,*r=head;
        if(head==NULL || head->next==NULL) {
     
            return NULL;
        }
        
        while(r && r ->next){
     
            l=l->next;
            r=r->next->next;
            if(l==r){
     
                ListNode *tmp=head;
                while(tmp!=l){
     
                    tmp=tmp->next;
                    l=l->next;
                }
                return tmp;
            }
        }
        
        return NULL;
    }
};



你可能感兴趣的:(leetcode,链表)