链表经典OJ问题【环形链表】

news2025/1/11 21:43:24

题目导入

题目一:给你一个链表的头节点 head ,判断链表中是否有环
题目二:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL。

题目一

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

分析

这里我们不能用单个指针来判断是否带环,这样是行不通的,因为我们不知道结束条件是什么;可能有人会想“让单个指针与带环链表的入口进行对比”,但是这有个问题,我们并不知道哪个节点是这个环形链表的节点。
类似下图
在这里插入图片描述

尾节点的next指向哪里是不确定的,有可能指向头节点,也有可能指向其他节点(极端情况指向自己),还有可能就不是一个环形链表(指向NULL)。

所以这里要使用快慢指针(这是一个很棒的解题思路),在这个题我们就让慢指针走一步,快指针走两步。
具体代码如下

struct ListNode* slow = head , *fast = head;
slow = slow->next;//慢指针走一步
fast = fast->next->next;//快指针走两步

这个指针不可能只会走一次的,所以是需要循环来完成的

bool hasCycle(struct ListNode *head) {
    struct ListNode* slow = head , *fast = head;
    while()
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return false;//链表不为环形链表
    
}

这里的结束条件是什么呢?
这里是判断该链表是否为环形链表,所以我们的判断条件是fast != NULL && fast->next != NULL
这里为什么要判断fast->next呢,假设这条链表不是环形链表,且fast->next是指向NULL,如果我们不对 fast->next进行判断的话,进入循环就会出现fast->next已经为空,我们还对他进行了解引用,这样就会报错
所以这里的结束条件为

while(fast && fast->next)
{
	…………//代码段
}

好了,循环已经写好了,那么来写结束条件吧(判断是否带环),不能说因为代码死循环了就说链表是环形链表吧。
当slow等于fast时就表示该链表为环形链表。
为什么呢?
我们借图来了解:

开始将head赋予给slow和fast开始将head赋予给slow和fast
因为fast指针的行走速度是slow指针的两倍,所以当slow走了链表的中间节点时,fast就已经走到尾节点了。
在这里插入图片描述

slow走到尾节点时,就代表slow也进环了,这时候就成了追击问题,当fast == slow时,就代表该链表是环形链表。
完整代码如下:

bool hasCycle(struct ListNode *head) {
    struct ListNode* slow = head , *fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)//相等,代表为环形链表
        {
            return true;
        }
    }
    return false;//不是环形链表
}

题目衍生问题

  1. 为什么一定为相遇,难道不会错过了,再也无法相遇呢?
  2. 如果我的fast走的不是两步,而是三步,四步或者更多呢?

衍生问题一

要证明这个很简单。
slow走到尾节点时,就代表slow也进环了,但这时候的fast的位置是不确定(可能已经转了好多圈了),所以我们假设fastslow的距离为N
如图:
在这里插入图片描述
因为fast是slow的两倍,所以追击一次,他俩之间的距离就会减一,一直追击下去距离就会一直减一,直到为0,也就是他两相等了

距离:N -> N-1 -> N-2 -> ……-> 2 -> 1 -> 0

因为fast是slow的两倍,所以每追击一次,他们的距离就会减一,所以他们两个不会错过。

衍生问题二

我们拿fast一次走三步来举例(其他的证明过程都大差不多,无非就是更复杂了)。
这时fast的速度就是slow的三倍,这时每追击一次,距离就会减二,这时候就要考虑两个情况了

  • 情况一:他们两个之间的距离为偶数
    这很简单,因为N为偶数,所以N%2=0;所以他们一定会在第一轮相遇。
  • 情况二:距离为奇数
    这样追击下去,当他们之间的距离为1时,在追击一次后,fast就会跑到slow的前面,开启新一轮的追击

N为奇数: N -> N-2 -> N-4 -> …… -> 5 -> 3 -> 1 -> -1

假设这个环形链表的长度为C。
这时候又要看两种情况这个C-1是否为偶数;
当C-1为偶数时,那么就和情况一一样,就一定会相遇。
如果C-1还是奇数,那就真的永远都遇不到了。

那么真的会出现N为奇数,C为偶数(C-1为奇)的情况吗?
其实是不可能的,我们将他们进行换算就可以知道为什么了。
在这里插入图片描述

总结论:使用快慢指针,环形链表一定会相遇,如果N为偶数,那么C一定为偶数;N为奇数,C一定为奇数。

题目二

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

这里就是在判断环形链表的基础上再加一些要求,那前置的代码,可以直接使用上面的代码

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow = head , *fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)//相遇了
        {
			
        }
    }
    return NULL;//无环
}

那既让相遇了,我们肯定就是在相遇之后进行操作,也就是在if语句里写代码。
既让已经相遇了,那么slow的步数就为L+N(slow在环内走了 N 步),fast的步数就为L + x*C + N(走了一圈x就加1,然后因为slow在环内走了 N 步,使用就为x*C+N)。
我们将slowfast相遇时的节点,给到meet

        if(slow == fast)//相遇了
        {
			struct ListNode* meet = slow;//这里给fast也行
        }

我们看图来进行换算:
在这里插入图片描述
完整代码:

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow = head , *fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
        {
            struct ListNode* meet = slow;
            while(meet != head)//同时走
            {
                meet = meet->next;
                head = head->next;
            }
            return meet;//走到这里就代表meet == head
        }
    }
    return NULL;
}

其实这两题本意都不难,难的是衍生问题和背后的数学逻辑(其实拆开了也不难),所以这也成了以前面试时会考的点,
考察的是你的逻辑思维。

结语

最后感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言,也可以前往我的主页看更多好文哦(点击此处跳转到主页)。
如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!!!

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

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

相关文章

什么是物联网通信网关?-天拓四方

在信息化、智能化的时代,物联网技术的广泛应用正在逐渐改变我们的生活方式。物联网通过各种传感器和设备,将现实世界与数字世界紧密相连,从而实现智能化、自动化的生活和工作方式。作为物联网生态系统中的重要组成部分,物联网通信…

Q-Learning学习笔记-李宏毅

introduction 学习的并不是policy,而是学习critic,critic用来评价policy好还是不好;一种critic:state value function V π ( s ) V^\pi(s) Vπ(s)是给定一个policy π \pi π,在遇到state s s s之后累积的reward的…

并发控制利器Semaphore

并发控制利器:Semaphore详解与应用 简介 Semaphore 是Java并发编程中的一个重要工具,用于管理对共享资源的访问权限,确保系统资源不会因过度访问而耗尽。形象地说,Semaphore 可以比喻为交通信号灯,它控制着能够同时进…

Spring Cloud 系列之Gateway:(9)初识网关

传送门 Spring Cloud Alibaba系列之nacos:(1)安装 Spring Cloud Alibaba系列之nacos:(2)单机模式支持mysql Spring Cloud Alibaba系列之nacos:(3)服务注册发现 Spring Cloud 系列之OpenFeign:(4)集成OpenFeign Spring Cloud …

探索 JavaScript 新增声明命令与解构赋值的魅力:从 ES5 迈向 ES6

个人主页:学习前端的小z 个人专栏:JavaScript 精粹 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结,欢迎大家在评论区交流讨论! ES5、ES6介绍 文章目录 💯声明命令 let、const🍟1 let声明符&a…

【区块链】caliper压力测试

本文上接postman接口测试 参照工程项目使用Caliper测试工具对食品安全溯源系统智能合约生成新食品(newFood)功能进行压力测试 首先启动webase python3 deploy.py startAll vim /opt/bencahmark/caliper-benchmark/networks/fisco-bcos/test-nw/fisco-bcos.json 命令便捷查…

刷代码随想录有感(75):回溯问题——非递减子序列

题干&#xff1a; 代码&#xff1a; class Solution { public:vector<int> tmp;vector<vector<int>> res;void backtracking(vector<int> nums, int start){if(tmp.size() > 2){res.push_back(tmp);}unordered_set<int> uset;for(int i sta…

JMeter 基本使用【Windows Jmeter GUI 图形界面】

1.安装jmeter GUI图形界面 需要安装JDK 官方网址: Apache JMeter - Apache JMeter™ linux tgz windows zip 2. 目录及文件 bin: 核心可执行文件&#xff0c;包含配置 extras&#xff1a;插件扩展包 lib&#xff1a;核心依赖包 ext&#xff1a;核心包 junit&#xff1a;单…

低代码开发:成本革命,还是技术幻象?

在当今快速发展的数字化时代&#xff0c;企业面临着不断增长的技术需求和日益紧缩的预算压力。开源低代码开发平台&#xff08;YDUIbuilder&#xff09;应运而生&#xff0c;承诺以更低的成本和更快的速度交付应用程序。但低代码开发真的能减少成本吗&#xff1f;本文将深入探讨…

uniapp集成websocket不断线的处理-打牌记账

背景 近期在开发打牌记账微信小程序时&#xff0c;我们将房间这个业务场景做成了类似聊天室功能。 对房间内发生的动作&#xff0c;都能实时对其他人可见。 如:转账&#xff0c;离开&#xff0c;加入&#xff0c;结算等动作 其他人员都能实时接收到推送消息&#xff0c; 这个时…

自媒体多平台互助平台_互赞互关,视频快速起流

首先&#xff0c;视频爆流的关键规则是什么&#xff1f; 平台根据视频的点赞/评论数据计算视频热门程度&#xff0c; 视频播放留存与收藏等等也在考核范围内&#xff0c; 不过&#xff0c;互关互赞不一定符合推流&#xff01;这你要清楚&#xff01;&#xff01; 目前我还不能准…

Doris【部署 03】Linux环境Doris数据库部署异常问题收集解决(不断更新)

Linux环境Doris数据库部署异常问题 1.FE1.1 Unknown system variable character_set_database1.2 notify new FE type transfer: UNKNOWN1.3 mysql_load_server_secure_path1.4 Only unique table could be updated1.5 too many filtered rows 2.BE2.1 Have not get FE Master …

vue项目报错:internal/modules/cjs/loader.js:892 throw err;

前言&#xff1a; vue项目中无法正常使用git&#xff0c;并报错情况。 报错信息&#xff1a; internal/modules/cjs/loader.js:892throw err;^ Error: Cannot find module D:\project\sd_wh_yth_front\node_modules\yorkie\src\runner.js 报错处理&#xff1a; npm install y…

【多模态融合】Cross Modal Transformer: Towards Fast and Robust 3D Object Detection

论文链接&#xff1a;Cross Modal Transformer: Towards Fast and Robust 3D Object Detection 代码链接&#xff1a;https://github.com/junjie18/CMT 作者&#xff1a;Junjie Yan, Yingfei Liu, Jianjian Sun, Fan Jia, Shuailin Li, Tiancai Wang, Xiangyu Zhang 发表单位…

运维笔记.MySQL.基于mysqldump数据备份与恢复

运维专题 MySQL.基于mysqldump数据备份与恢复 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: [email protected]. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_2855…

提升主播直播体验:如何选择和使用第三方美颜SDK?

第三方美颜SDK为开发者提供了实现这些功能的便利途径。那么&#xff0c;如何选择和使用第三方美颜SDK&#xff0c;来提升主播的直播体验呢&#xff1f; 一、了解美颜SDK的重要性 1.1美颜SDK的作用 美颜SDK不仅能提升主播的自信&#xff0c;还能吸引更多观众&#xff0c;增加…

“智绘艺术家之诗画点军”正式报名开赛 |AIGC与点军的梦幻碰撞,等你来战!

点军&#xff0c;这处江南的明珠&#xff0c;宜昌的瑰宝&#xff0c;历史与自然的交响乐章在此奏响。 三国时&#xff0c;关羽曾在此点兵&#xff0c;其雄姿英发&#xff0c;至今犹在眼前。 古之要塞&#xff0c;控巴夔&#xff0c;制荆襄&#xff0c;为三峡门户&#xff0c;…

“Excel+中文编程”衍生新型软件,WPS用户:自家孩子

你知道吗&#xff0c;我们中国人有时候真的挺有创新精神的。 你可能熟悉Excel表格&#xff0c;也可能听说过中文编程&#xff0c;但你有没有脑洞大开&#xff0c;想过如果把这两者结合起来&#xff0c;会碰撞出什么样的火花呢&#xff1f; 别不信&#xff0c;跟着我来看看吧&a…

【mysql】【docker】mysql8-互为主从

&#x1f338;&#x1f338; Linux/docker-compose/mysql8 互为主从 优雅部署 &#x1f338;&#x1f338; 记录下两台Linux的mysql需要热备份&#xff0c;互为主从&#xff0c;后期加上keepalived实现高可用切换 参考博客&#xff1a;答 案 &#x1f338; 一、准备文件 这里…