【环形链表(带环链表)超详细总结】

news2024/10/5 16:24:27

题目一

给你一个链表的头节点 head ,判断链表中是否有环

使用快慢指针,如果慢指针等于快指针,就说明是带环链表

链表的中间结点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode* slow = head;
    struct ListNode* fast = head;

    // 奇数结点 与 偶数结点 两种情况
    while(fast && fast->next){
        //奇数结点:5
        //1 2 3 4 5
        //slow 1 2 3
        //fast 1 3 5
        //fast的next为NULL
        slow = slow->next;
        fast = fast->next->next;
        //偶数结点:4
        //1 2 3 4 
        //slow 1 2 3
        //fast 1 3 NULL
        //fast为NULL
        if(slow == fast)
            return true;
    }
    return false;
}

题目二

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* m = head;
    struct ListNode* k = head;

    while((k!=NULL)&&(k->next!=NULL))
    {
        m = m->next;
        k = k->next->next;
        if(m == k)//证明是带环链表
        {
            while(head!=m)//让头指针开始和慢指针开始走(相等时候就是入环的第一个结点)
            {
                m = m->next;
                head = head->next;
            }
            return m;//或者head
        }
    }
    return NULL;
}

扩展知识点

慢指针每次走一步,快指针每次走两步,那么一定可以追上吗?

一定可以追上

当slow进入环之后,fast才开始追击slow,假设slow入环的时候,它们之间的距离为N。每追击一次,它们之间的距离缩小一。
在这里插入图片描述
在追击过程中,它们之间的距离变化为:

N、N-1、N-2、......1、0(追上了)

慢指针每次走一步,快指针每次走三步,那么一定可以追上吗?

当slow进入环之后,fast才开始追击slow,假设slow入环的时候,它们之间的距离为M。每追击一次,它们之间的距离缩小二·。

M、M-2、M-4、......
如果M是偶数:...4、2、0(追上了)
如果M是奇数:...3、1、-1(-1表示fast走在了slow前面一个位置)

在这里插入图片描述
而距离为1表示(fast在slow的后一个位置上)
在这里插入图片描述
距离为-1表示开始了新一轮的追击(追击的距离为C-1)其中C是环的长度(周长)

判断(C-1是偶数还是奇数):

如果是偶数,那么在下一轮的追击上一定可以追上(0)
如果是奇数,那么在下一轮的追击上一定不可以追上(-1)

慢指针每次走一步,快指针每次走四步,那么一定可以追上吗?


当slow进入环之后,fast才开始追击slow,假设slow入环的时候,它们之间的距离为K。每追击一次,它们之间的距离缩小三。

K、K-3、K-6、...

如果K是三的倍数,那么就一定会相遇(K%3 == 0)

K、K-3、K-6、...、6、3、0

if (K%3 == 2)

K、K-3、K-6、...、8、5、2、-1(C-1)

if (K%3 == 1)

K、K-3、K-6、...、10、7、4、1、-2(C-2)

在这里插入图片描述
请添加图片描述

这只是一种特殊情况(并不是正确的规律)

请添加图片描述
请添加图片描述
请添加图片描述

请添加图片描述


请添加图片描述
结论:
一个指针从起点开始走(head),一个指针从相遇点开始走(meet),它们会在环的入口点相遇。


还可以使用相交链表的思想去解决问题2

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode * testa = headA;
    struct ListNode * testb = headB;

    //先去计算一下两个链表的长度
    int lena = 0;
    int lenb = 0;

    while(testa!=NULL){
        testa = testa->next;
        lena++;
    }
    
    while(testb!=NULL){
        testb = testb->next;
        lenb++;
    }

    int lensum = abs(lena-lenb);

    struct ListNode * longnode = headA;
    struct ListNode * smartnode = headB;

    if(lena<lenb){
        longnode = headB;
        smartnode = headA;
    }

    while(lensum--){
        longnode = longnode->next;
    }

    while(longnode != smartnode){
        longnode = longnode->next;
        smartnode = smartnode->next;
    }
    return longnode;
}
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* m = head;
    struct ListNode* k = head;

    while((k!=NULL)&&(k->next!=NULL))
    {
        m = m->next;
        k = k->next->next;
        if(m == k)//证明是带环链表
        {
            struct ListNode* meet = m;
            struct ListNode* newhead = meet->next;
            meet->next = NULL;

            //相交链表
            
            //head
            //newhead

            int lena = 0;
            int lenb = 0;
            struct ListNode* testa = head;
            struct ListNode* testb = newhead;
            //记得这里要先去找test去遍历计数
            while(testa!=NULL){
                testa = testa->next;
                lena++;
            }
            while(testb!=NULL){
                testb = testb->next;
                lenb++;
            }
            
            int slen = abs(lena-lenb);
   
            struct ListNode* longnode = head;
            struct ListNode* smartnode = newhead;
   
            if(lena<lenb){
                longnode = newhead;
                smartnode = head;
            }
   
            while(slen--){
                longnode = longnode->next;
            }
   
            while(longnode!=smartnode){
                longnode = longnode->next;
                smartnode = smartnode->next;
            }
   
            return longnode;
            //或者使用接口函数就行
            // return getIntersectionNode(head,newhead);
        }
    }
    return NULL;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/827572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是 webpack?

Webpack 介绍 什么是 webpack&#xff1f; :::tip 官方描述 webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时&#xff0c;它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)&#xff0c;然后将你项目中所需的每一个…

Zookeeper基础操作

搭建Zookeeper服务器 windows下部署 下载地址: https://mirrors.cloud.tencent.com/apache/zookeeper/zookeeper-3.7.1/ 修改配置文件 打开conf目录&#xff0c;将 zoo_sample.cfg复制一份&#xff0c;命名为 zoo.cfg打开 zoo.cfg&#xff0c;修改 dataDir路径&#xff0c…

0802|IO进程线程day5 作业(打印时钟在终端上,若终端输入quit,结束时钟)

作业1&#xff1a;守护进程 守护进程的创建&#xff08;5步&#xff09;&#xff1a; 创建孤儿进程&#xff1a;所有工作都在子进程中执行&#xff0c;从形式上脱离终端控制。 fork(), 退出父进程 创建新的会话组&#xff1a;使子进程完全独立出来&#xff0c;防止兄弟进程对其…

蓝桥杯上岸必背!!!(并查集补更)

蓝桥杯上岸必背&#xff01;&#xff01;&#xff01;(并查集补更) 大家好 我是寸铁&#x1f4aa; 冲刺蓝桥杯省一模板大全来啦 &#x1f525; 蓝桥杯4月8号就要开始了 &#x1f64f; 距离蓝桥杯省赛倒数第3天 ❗️ ❗️ ❗️ 还没背熟模板的伙伴们背起来 &#x1f4aa; &…

git 常用命令有哪些

Git 是我们开发工作中使用频率极高的工具&#xff0c;下面总结下他的基本指令有哪些&#xff0c;顺便温习一下。 前言 一般项目中长存2个分支&#xff1a; 主分支&#xff08;master&#xff09; 和开发分支&#xff08;develp&#xff09; 项目存在三种短期分支 &#xff1a…

大数据技术之Clickhouse---入门篇---SQL操作、副本

星光下的赶路人star的个人主页 积一勺以成江河&#xff0c;累微尘以崇峻极 文章目录 1、SQL操作1.1 Insert1.2 Update 和 Delete1.3 查询操作1.4 alter操作1.5 导出数据 2、副本2.1 副本写入流程2.2 配置步骤 1、SQL操作 基本上来说传统关系型数据库&#xff08;以 MySQL 为例…

忘记数据库密码如何处理

windows 5.6.51版本及以前 #当前账号设置密码 set password password(123456); #当前账号取消密码 set password ; &#xff08;1&#xff09;用管理员身份打开控制台输入 net stop m5&#xff08;我的电脑MySQL名字为m5&#xff0c;根据自己的更改&#xff09; &#xff08;…

爱尔眼科四川省区“同心博爱 光明工程”“西部健康公益行”炉霍站启动

8月1日&#xff0c;“同心博爱 光明工程”“西部健康公益行”炉霍站出征仪式在四川爱尔眼科医院隆重举行。 此次公益活动由民革成都市委会、中共锦江区委统战部指导&#xff0c;如意树爱心促进会主办&#xff0c;民革锦江区总支部、爱尔眼科四川省区支持&#xff0c;四川爱尔眼…

Linux系统CPU和磁盘性能进程分析工具pidstat

一、pidstat对CPU的分析 Linux 上的pidstat(1)工具按进程或线程打印CPU 用量&#xff0c;包括用户态和系统态时间的分解。默认情况下&#xff0c;仅循环输出活动进程的信息。例如&#xff1a; 这个例子捕捉到了系统备份&#xff0c;包含了tar(1)命令&#xff0c;从文件系统读取…

低通、高通、带通、阻通滤波器

目录 低通、高通、带通、阻通滤波器 低通、高通、带通、带阻滤波器的区别 通俗理解&#xff1a; 1、低通滤波器 2、高通滤波器 3、带通滤波器 4、带阻滤波器 5、全通滤波器 低通、高通、带通、阻通滤波器 低通、高通、带通、带阻滤波器的区别 低通滤波器&#xff1a;只…

运维高级--tomcat和jpress

1. 简述静态网页和动态网页的区别。 静态网页&#xff1a;事先创建好的网页&#xff0c;通常通过HTML、CSS和JavaScript等静态文件组成&#xff0c;不需要和服务器进行交互&#xff0c;加载速度快 动态网页&#xff1a;根据用户需求动态生成网页&#xff0c;动态网页通常使用…

3D软件性能的基准测试工具,侧重于测试处理器和显卡,赶紧试试

如果需要&#xff0c;Cinebench 可帮助您评估计算机执行渲染任务的性能。Cinebench 由 Maxon 开发&#xff0c;利用行业标准基准测试技术来评估您的系统在要求苛刻的图形任务中的性能。 它主要侧重于测试处理器和显卡&#xff0c;以确定其渲染复杂 3D 图像和动画的效率。Cineb…

Spring 容器原始 Bean 是如何创建的?

以下内容基于 Spring6.0.4。 这个话题其实非常庞大&#xff0c;我本来想从 getBean 方法讲起&#xff0c;但一想这样讲完估计很多小伙伴就懵了&#xff0c;所以我们还是一步一步来&#xff0c;今天我主要是想和小伙伴们讲讲 Spring 容器创建 Bean 最最核心的 createBeanInstan…

笔试编程题常用框架/方法

目录 考核方式 ACM模式 JavaScript(V8) JavaScript(Node) 数组 折半 / 二分查找 螺旋矩阵* 前缀和-区间求和 差分数组-区间增减 滑动窗口-子串 链表 双指针&#xff08;快慢指针&#xff09; 有序数组的平方 删除/覆盖数组元素 最小长度的子数组 三数之和abcta…

【RTT驱动框架分析05】-spi驱动框架分析

spi 1.应用层的spi操作 spi 消息结构 struct rt_spi_message {const void *send_buf;//发送数据的缓存void *recv_buf;//接收数据的缓存rt_size_t length;//数据长度struct rt_spi_message *next;//指向下一个消息结构unsigned cs_take : 1;//是否执行获取csunsigned cs_…

SQL-每日一题【1174. 即时食物配送 II】

题目 配送表: Delivery 如果顾客期望的配送日期和下单日期相同&#xff0c;则该订单称为 「即时订单」&#xff0c;否则称为「计划订单」。 「首次订单」是顾客最早创建的订单。我们保证一个顾客只会有一个「首次订单」。 写一条 SQL 查询语句获取即时订单在所有用户的首次订…

零碎小知识点汇总——记录工作中遇到的问题——基础积累

1.npm install安装包时&#xff0c;常用的-S -D有什么区别&#xff1f; 参考链接&#xff1a;https://blog.csdn.net/sunyctf/article/details/127667543 主要的区别就是依赖配置写入package.json文件的位置不同而已 npm install有一个别名&#xff1a;npm i -S:写入dependen…

抢夺本地生活万亿蛋糕:“抖音美团们”的攻防战

有人就有市场&#xff0c;有市场就有竞争。面对本地生活这一大“富矿”&#xff0c;互联网大厂们正在开启一场争夺战。 前有抖音、小红书在团购业务上火速推进&#xff0c;近日&#xff0c;随着拼多多正式上线本地生活入口&#xff0c;这个领域的玩家越来越多。 艾瑞咨询数据…

Linux中的特殊进程(孤儿进程、僵尸进程、守护进程)

一、孤儿进程 1&#xff09;父进程退出&#xff0c;子进程不退出&#xff0c;此时子进程被1号&#xff08;init&#xff09;进程收养&#xff0c;变成孤儿进程。 2&#xff09;孤儿进程会脱离终端控制&#xff0c;且运行在后端&#xff0c;不能用ctrlc杀死后端进程&#xff0c;…

Linux ALSA音频工具aplay、arecord、amixer的使用方法

ALSA 是Advanced Linux Sound Architecture的缩写&#xff0c;先进的Linux音频架构&#xff0c;为Linux操作系统提供音频和MIDI功能。 aplay命令 aplay是播放命令。 rootimx6ul7d:~# aplay -h Usage: aplay [OPTION]... [FILE]...-h, --help help--version …