【LeetCode】带环链表两道题

news2025/1/16 14:06:44

第一题:环形链表

问题介绍

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

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

如果链表中存在环 ,则返回true。 否则,返回false

问题设置:

  • 链表中节点的数目范围是 [0, 10^4]
  • -10^5 <= Node.val <= 10^5
  • pos-1或者链表中的一个有效索引

问题解释:

问题的函数接口传过来的是不带哨兵位的单链表。
可以使用快慢指针来解决。先让快指针和慢指针都指向链表的起始结点,快指针一次走两步,慢指针一次走一步。
如果是带环链表,快指针先进环,慢指针后进环,就成了追及问题。
如果不是带环链表,快指针会走到空,此时结束。

一些问题分析

  • 那为什么快指针一次走两步,慢指针一次走一步,快指针就一定能在环内追上慢指针,和慢指针相遇呢?
    当快慢指针都进环后,
    最好的情况是,慢指针一进环,就和快指针相遇,程序就结束。
    最坏的情况是,慢指针一进环,快指针在慢指针的前一个位置。
    假设环内的结点数为N,此时快指针和慢指针相差了N-1步,
    因为快指针一次走两步,慢指针一次走一步,每次快指针都比慢指针多走一步,(N-1)的差值会不断减1,直到减为0。
    所以慢指针走N-1步后,快指针就会追上慢指针和慢指针相遇。
    可以发现:在慢指针进环后,快指针一定可以在慢指针走完一圈之前追上慢指针和慢指针相遇。

  • 那为什么一定是快指针一次走两步,慢指针一次走一步才行,快指针一次走三步,走四步等等不行吗?
    首先快指针一次走的步数如果大于两步,循环结束的判断条件会更不好控制是一方面;
    同时,像上一个问题分析的,如果慢指针进环后,快指针和慢指针的差距步是N-1,
    当快指针一次走三步,慢指针一次走一步,快指针和慢指针每走一次,差距步就缩减两步。
    如果N是奇数的情况下,N-1是偶数,(N-1)不断以两步的速度缩减,最终会减为0,也就是快指针追上慢指针和慢指针相遇了
    但如果N是偶数的情况下,N-1是奇数,(N-1)不断以两步的速度缩减(也就是:N-1,N-3,…,3,1,-1);差距步并不能减为0,也就是快指针能追上慢指针,但会和慢指针擦肩而过,直到差距步减为-1的情况出现,快指针又恰好处于慢指针的前一个位置,差距步又恢复为N-1,这就导致在某些极端场景下,出现快指针永远追不上慢指针的问题。

快指针一次走四步等情况,也是类似的道理,就不再赘述。

如果你非要抬杠说,让快指针一次走三步,慢指针一次走两步,进环后差距步也是每次缩减1步,快指针最后也会追上慢指针并和慢指针相遇,不是吗?
那我只能说:对对对,你说得对!

参考代码

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

	//因为fast一次走两步,所以需要同时判断fast和fast->next是不是NULL
    while(fast!=NULL&&fast->next!=NULL)
    {
        slow=slow->next;
        fast=fast->next->next;

        if(slow==fast)
        {
            return true;
        }
    }
    return false;
}

第二题:环形链表 II

问题介绍

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

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

不允许修改链表。

问题设置

链表中节点的数目范围在范围[0, 10^4]
-10\^5 <= Node.val <= 10\^5
pos的值为-1或者链表中的一个有效索引

问题解释

这道题相较上一道题,需要返回带环链表的入环结点。

问题的函数接口传过来的也是不带哨兵位的单链表。

解决这道题需要画图和进行简单的数学分析
在这里插入图片描述
假设H为链表的起始点,E为入口点,M为相遇点,
H到E的距离为L,环的大小为R,E到M的距离为X,则M到E的距离为R-X

当快指针和慢指针在M点相遇时,
慢指针走过的距离是:L+X;
快指针走过的距离是:L+n*R+X(n>=1);
在第一题中已经分析:
最好的情况是,慢指针一进环,就和快指针相遇,程序就结束,
此时对于快指针来说,n恰好是1;
最坏的情况是,慢指针一进环,快指针在慢指针的前一个位置,
此时慢指针需要走N-1步,快指针自然要走2倍的N-1步,快指针如果想追上慢指针,就必须先到达入口点E,最终n也可以说是大于等于1的。

但是,这样说未免有失偏颇。
当L很短,而R很大的时候,上述情况可能还说得过;
但如果L很长,R很小,在慢指针还未入环的时候,快指针已经在环内跑了好几圈,这就是另一种情况了。
所以可得出n是大于等于1的。

有了上述的铺垫,可以列出数学等式:
2(L+X) = L+nR+X
=> L+X = n
R = (n-1)*R+R
=> L= (n-1)R+R-X

这说明什么呢?
也就是说,有两个指针,一个从H点出发,一个从M点出发,当他们相遇时,他们共同所指的结点就是带环链表的入环结点。
是不是很神奇,下面用代码验证一下吧。

参考代码

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

    while(fast!=NULL&&fast->next!=NULL)
    {
        slow=slow->next;
        fast=fast->next->next;
		
		//找到相遇点
        if(slow==fast)
        {
            struct ListNode* cur1=head;
            struct ListNode* cur2=slow;

            while(cur1!=cur2)
            {
                cur1=cur1->next;
                cur2=cur2->next;
            }

            return cur1;
        }
    }
    return NULL;
}

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

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

相关文章

【Storm】【三】Storm 核心概念详解

Storm 核心概念详解 一、Storm核心概念1.1 Topologies&#xff08;拓扑&#xff09;1.2 Streams&#xff08;流&#xff09;1.3 Spouts1.4 Bolts1.5 Stream groupings&#xff08;分组策略&#xff09;二、Storm架构详解2.1 nimbus进程2.2 supervisor进程2.3 zookeeper的作用2.…

【蒸滴C】C语言结构体入门?看这一篇就够了

目录 一、结构体的定义 二、结构的声明 例子 三、 结构成员的类型 结构体变量的定义和初始化 1.声明类型的同时定义变量p1 2.直接定义结构体变量p2 3.初始化&#xff1a;定义变量的同时赋初值。 4.结构体变量的定义放在结构体的声明之后 5.结构体嵌套初始化 6.结构体…

24节气-惊蛰 // 诗句、海报分享,春风至,惊雷动。

惊蛰&#xff0c;古称"启蛰"&#xff0c;是二十四节气中的第3个节气&#xff0c;更是干支历卯月的起始;时间点在公历3月5-6日之间&#xff0c;太阳到达黄经345时。《月令七十二候集解》:"二月节……万物出乎震&#xff0c;震为雷&#xff0c;故曰惊蛰&#xff0…

【ONE·C || 动态内存管理】

总言 C语言&#xff1a;动态内存管理介绍。 文章目录总言1、为什么存在动态内存管理2、动态内存函数介绍2.1、malloc、free2.1.1、malloc函数2.1.2、free函数2.2、calloc、realloc2.2.1、calloc函数2.2.2、realloc函数3、常见的动态内存错误3.1、对NULL指针的解引用操作3.2、对…

TEX:显示文本

文章目录字体选择字体fontspec宏包根据字体形状控制字体为不同的字体形状选择不同的特征为不同的字体大小状选择不同的特征中文字体选择xeCJK宏包字体选择与设置XELATEX字体名查找字体集与符号居中与缩进居中单边调整两边缩进诗歌缩进列表itemize样例enumerate样例description样…

Java多线程(三)——线程池及定时器

线程池就是一个可以复用线程的技术。前面三种多线程方法就是在用户发起一个线程请求就创建一个新线程来处理&#xff0c;下次新任务来了又要创建新线程&#xff0c;而创建新线程的开销是很大的&#xff0c;这样会严重影响系统的性能。线程池就相当于预先创建好几个线程&#xf…

concrt140.dll丢失四种方法解决丨提示游戏里找不到concrt140.dll?

电脑提示concrt140.dll文件丢失怎么办&#xff1f;由于找不到concrt140.dll&#xff0c;无法继续执行代码&#xff1f; 我们平时在打开 Adobe 应用程序、Halo、Forza Horizon 5 地平线5 等时&#xff0c;可能会遇到找不到 concrt140.dll。因此&#xff0c;这不是特定于某个应用…

基频的后处理

基频归一化 基频为什么要归一化&#xff1f;为了消除人际随机差异&#xff0c;提取恒定参数&#xff0c;在语际变异中找到共性。 引言 声调的主要载体就是基频。但是对声调的感知会因人而异&#xff0c;例如某个听感上的高升调&#xff0c;不同的调查人员可能会分别描写成 […

Nginx的负载均衡

Nginx不仅可以作为一个web服务器或反向代理服务器&#xff0c;还可以按照权重、轮询、ip_hash、URL_hash等多种方式实现对后端服务器的负载均衡。 负载均衡的概念&#xff1a; 负载均衡就是将负载分摊到多个操作单元上执行&#xff0c;从而提高服务的可用性和相应速度&#xf…

数据仓库、数据中台、数据湖都是什么?

相信很多人都在最近的招聘市场上看到过招聘要求里提到了数据仓库、数据中台&#xff0c;甚至还有数据湖&#xff0c;这些层出不穷的概念让人困扰。今天我就来跟大家讲一讲数据仓库、数据中台以及数据湖的概念及区别。 数据库 在了解数据仓库、数据中台以及数据湖之前&#xff…

JDBC

JDBC核心技术 讲师&#xff1a;宋红康 微博&#xff1a;尚硅谷-宋红康 第1章&#xff1a;JDBC概述 1.1 数据的持久化 持久化(persistence)&#xff1a;把数据保存到可掉电式存储设备中以供之后使用。大多数情况下&#xff0c;特别是企业级应用&#xff0c;数据持久化意味着将内…

【java web篇】Tomcat的基本使用

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

ceph介绍、原理、架构、算法...个人学习记录

前言 之前公司安排出差支援非结构化项目&#xff0c;采用springcloud(redismysql数据冷热处理)s3escephkafka还涉及一些区块链技术等等…&#xff0c;在与大佬的沟通交流下对ceph产生了兴趣&#xff0c;私下学习记录一下&#xff1b;后续工作之余会采用上面相关技术栈手动实现不…

Python模块化编程_Python编程之路

之前跟大家讲的是一些python的数据基础&#xff0c;从这篇文章开始&#xff0c;我们开始正式学习python的模块化编程 下面我们解释一下什么叫做模块 之前已经讲过怎么去定义一个方法&#xff0c;如果你是用python交互器(自带交互器&#xff0c;或者是ipython)来学习定义方法的…

4 通道 3.2GSPS(2 通道 6.4GSPS) 12 位 AD 采集子卡模块

FMC134 是一款 4 通道 3.2GSPS&#xff08;或者配置成 2 通道 6.4GSPS&#xff09; 采样率的 12 位 AD 采集 FMC子卡模块&#xff0c;该板卡为 FMC标准&#xff0c;符 合 VITA57.4 规范&#xff0c;可以作为一个理想的 IO 模块耦合至 FPGA 前端&#xff0c; 射频模拟信号数字化…

c语言经典例题-循环结构程序设计

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 求各位数字之积&#xff1a; 本关任务&#xff1a;计算正整数num的各位上的数字之积。 例如&#xff1a; 输入&am…

Elasticsearch:构建自动补全功能 - Autocomplete

什么是自动补全&#xff08;autocomplete&#xff09;功能呢&#xff1f;我们举一个很常见的例子。 每当你去谷歌并开始打字时&#xff0c;就会出现一个下拉列表&#xff0c;其中列出了建议。 这些建议与查询相关并帮助用户完成查询。 Autocomplete 正如维基百科所说的&#xf…

vulnhub raven2复现

1.扫描全网段&#xff0c;找出了存活主机ip为192.168.85.144 nmap 192.168.85.0/24 2.nmap扫描端口 nmap -p1-65535 192.168.85.144 3.访问此网站&#xff0c;没找到什么地方可以利用漏洞 &#xff0c;查看中间件为wordpress 4.使用dirb对该网站进行目录扫描 dirb http://1…

刷题笔记3 | 203. 移除链表元素、707设计链表,206.反转链表

目录 203. 移除链表元素 707、设计链表 206.反转链表 203. 移除链表元素 题意&#xff1a;删除链表中等于给定值 val 的所有节点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#xff1a; 输入&#xff1a;h…

18跨越语言:不同语言间进行RPC通信

在最开始介绍gRPC时我们讲到,gRPC具有灵活的兼容性,可以支持很多种编程语言,下面我们就使用在后端领域最常用的两种编程语言Go和Java,来体验一下gRPC在不同语言的项目间是如何进行通信的。 逻辑架构 由上图我们可以看出,Go语言设计gRPC的服务端,Java语言设计gRPC的客户端…