• 链表专项之环形链表



    前言


    1.141. 环形链表

    给你一个链表的头节点 head ,判断链表中是否有环。
    如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
    如果链表中存在环 ,则返回 true 。 否则,返回 false 。

    在这里插入图片描述

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     struct ListNode *next;
     * };
     */
    bool hasCycle(struct ListNode *head) {
        struct ListNode*fast=head;
        struct ListNode*slow=head;
        while(fast!=NULL&&fast->next!=NULL)
        {
            slow=slow->next;
            fast=fast->next->next;
             if(slow==fast)
            {
                return true;
            }
        }
       return false; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    这道题的思考还是比较简单的 使用快慢指针
    两者从head开始
    快指针每次走2步
    慢指针每次走1步
    如果是循环链表则 一定能使快指针追上慢指针
    也要注意一个问题 判断slow指针与fast指针是否相等 ,是在移动一次之后
    因为 开始定义的时候就是相等的

    证明为什么快指针一定为2步,慢指针一定为1步

    1.当循环链表前的距离与循环链表后的距离相等时

    在这里插入图片描述

       >当slow指针走到循环开始时,fast指针已经走完一圈了,所以两者处于相同位置
    
    • 1

    2.当循环链表前的距离为循环链表后的距离的1/2

    在这里插入图片描述

    fast一次走2步,slow一次走1步
    当slow走到循环开始的位置, fast已经走到循环的一半
    按照顺时针的顺序 fast追slow, 两者之间的距离为x
    当fast与slow每走一次则之间的距离减少1
    即x-1,x-2,x-3,x-4,x-5,x-6…
    无论x为奇数或者偶数 两者一定能相遇

    同种情况下,fast走N步,slow走1步

    依旧假设fast指针与slow指针之间的距离为x
    若fast指针一次走3步,slow指针一次走1步
    则slow与fast每走一次距离减少2
    x-2,x-4,x-6,x-8,x-10…
    x若为偶数则能成功遇见 ,若为奇数 就会一直错过 ,造成死循环

    同理 若fast指针一次走4步,slow指针一次走1步
    两者之间每次减少3
    x-3,x-6,x-9,x-12…
    若x为奇数则能成功遇见,若为偶数 就会一直错过,造成死循环

    142. 环形链表 II

    给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
    如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
    不允许修改 链表。

    在这里插入图片描述

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     struct ListNode *next;
     * };
     */
    struct ListNode *detectCycle(struct ListNode *head) {
        struct ListNode*fast=head;
        struct ListNode*slow=head;
        while(fast&&fast->next)
        {
            fast=fast->next->next;
            slow=slow->next;
            if(fast==slow)
            {
               struct ListNode*cur=slow;
                while(head!=cur)
                {
                    cur=cur->next;
                    head=head->next;
                }
                return cur;
    
            }
        }
         return NULL;
    
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    这道题需要一个公式,这个公式需要推导下
    它分为 正常情况与特殊情况

    公式的推导

    1.正常情况

    在这里插入图片描述

    fast走2步,slow走1步
    没循环的链表距离为L ,slow在循环链表中走的距离为X,循环链表一圈距离为C
    slow走的长度为L+X,fast在循环链表为L+C+X
    当fast与slow相遇时 fast是slow走的2倍
    即 2(L+X)=L+C+X
    L=C-X
    相当于head到交点的距离等于相遇点到交点的距离
    在这里插入图片描述

    2.特殊情况

    在这里插入图片描述

    没循环的链表距离为L ,slow在循环链表中走的距离为X,循环链表一圈距离为C
    当循环链表C很小时
    则当slow刚进入循环时,fast已经转了N圈
    当fast与slow相遇时
    即 2(L+X)=L+N * C+X
    即 L=N*C-X
    此时的N * C代表从相遇点处开始的N圈 减去x正好为相遇点
    所以N的数量不会影响
    依旧从fast与slow的相遇点开始 到交点的距离与head到交点的距离相等

  • 相关阅读:
    JS 拖拽事件
    SSD: Single Shot MultiBox Detector
    javascript 数组升序、降序
    遍历完全二叉树节点
    代码随想录算法训练营第六十天丨 单调栈03
    linux 部署dns正向解析服务,照做就可以
    数据结构——线性表:栈、队列
    【组合数学 隔板法 容斥原理】放球问题
    ADO.NET之sqlCommand对象
    idea设置某个文件修改后所在父文件夹变蓝色
  • 原文地址:https://blog.csdn.net/qq_62939852/article/details/126158133