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
由于快指针速度是慢指针的两倍,那么有: 2 ∗ ( L 1 + L 2 + N ∗ b ) = L 1 + L 2 + N ∗ a 2*(L_1+L_2+N*b)=L_1+L_2+N*a 2(L1+L2+Nb)=L1+L2+Na
化简得: L 1 + L 2 = ( a − 2 b ) ∗ N L_1+L_2=(a-2b)*N L1+L2=(a2b)N,即从出发点到两者相遇点的距离=环的长度的整数倍

此时需要求取 L 1 L_1 L1的长度,由 L 1 + L 2 = ( a − 2 b ) ∗ N L_1+L_2=(a-2b)*N L1+L2=(a2b)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;
    }
};



posted @ 2020-09-10 20:33  xzhws  阅读(41)  评论(0编辑  收藏  举报