【leetcode】141.环形链表

【leetcode】141.环形链表_第1张图片

【leetcode】141.环形链表_第2张图片 【leetcode】141.环形链表_第3张图片

分析:使用快慢指针,快指针一次走两步,慢指针一次走一步

快指针在环内追赶慢指针,如果两个指针相遇,则证明存在环

证明:

1️⃣环的起点为链表的尾节点,当fast指针到达环的起点时,slow指针走到链表的一半

【leetcode】141.环形链表_第4张图片2️⃣当slow指针到达环的起点时,fast指针指向环内的某个节点

【leetcode】141.环形链表_第5张图片

3️⃣此时快慢指针的差距为N,fast指针一次走两步,slow指针一次走一步,两个指针的差距每次缩小1,N次之后,两个指针的差距缩小为0,即两指针相遇

bool hasCycle(struct ListNode *head) {
    struct ListNode* slow, *fast;
    slow = fast = head;

    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        //快指针赶上了慢指针,存在环
        if(fast == slow)
        {
            return true;
        }
    }

    return false;
}


【leetcode】141.环形链表_第6张图片

【leetcode】141.环形链表_第7张图片

【leetcode】141.环形链表_第8张图片

方法一:

首先要判断链表是否有环,非环形链表返回NULL,环形链表才有下述操作

【leetcode】141.环形链表_第9张图片由上图:

fast指针每次走两步,slow指针每次走一步,所以有2(L+x) = L+x+N*C

L = N*C - x = (N-1)*C + C - x

如果有一个指针从头开始走,当它走过L到达环的入口时,有一个指针从相遇点meet走,他绕环N-1圈,再走C-x,同时也到达环的入口

所以我们使用两个指针,一个head链表头开始走,一个meet从相遇点开始走,每次走一步,当这两个指针不等时,head = head->next,meet = meet->next;当这两个指针相等时,即为环的入口节点

struct ListNode *detectCycle(struct ListNode *head) 
{
    struct ListNode* slow, *fast;
    slow = fast = head;
    struct ListNode* tail = head;
    

    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        //存在环,返回入环的第一个节点
        if (fast == slow)
        {
            //找到相遇点
            struct ListNode* meet = slow;
            while(meet != head)
            {
                meet = meet->next;
                head = head->next;
            }
            //相遇即为环的入口
            return meet;

        }
    }

    return NULL;    
}

方法二:转换成相交链表问题 

我们已经很熟练的可以找到环中fast指针和slow指针的相遇点

【leetcode】141.环形链表_第10张图片

由上图,我们可以将环形链表分成两部分

 一个以head作为头,meet作为尾

另一个以meet->next作为头,meet作为尾

环的入口是这两个链表相交的位置,已经讲述过链表相交问题【leetcode】160.相交链表_李斯啦果的博客-CSDN博客

因此求环的入口即转换成求两个链表相交位置的问题

Note

断开链表会更改原链表,因此求出交点后需要恢复原链表的结构

//方法二:转换成相交链表问题
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
    struct ListNode* curA = headA;
    struct ListNode* curB = headB;
    int lenA = 0;
    int lenB = 0;

    //统计长度    
    while (curA)
    {
        lenA++;
        curA = curA->next;
    }
    while (curB)
    {
        lenB++;
        curB = curB->next;
    }

    struct ListNode* longList = headA, * shortList = headB;
    if (lenA < lenB)
    {
        longList = headB;
        shortList = headA;
    }
    int gap = abs(lenA - lenB);

    //长链表先走差距步
    while (gap--)
    {
        longList = longList->next;
    }

    //同时走
    while (longList != shortList)
    {
        longList = longList->next;
        shortList = shortList->next;

    }

    return longList;

}
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow, *fast;
    slow = fast = head;
    struct ListNode* tail = head;
    
    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        //存在环,返回入环的第一个节点
        if (fast == slow)
        {
            //转换成相交链表问题
            struct ListNode* next = slow->next;
            //断开环
            slow->next = NULL;

            struct ListNode* entryNode = getIntersectionNode(head,next);
            //恢复环
            slow->next = next;
            return entryNode;

        }
    }

    return NULL;    
}

 

你可能感兴趣的:(实例,leetcode,链表,算法)