算法详解(力扣141——环形链表系列)

博主ID:代码小豪

文章目录

    • 环形链表
      • 环形链表的性质分析
      • 快慢指针法
      • 指针的追及相遇问题
    • 环形链表(2)

环形链表

先来看看环形链表的原题:

在这里插入图片描述
中间的部分叙述有点繁杂,简单来概括就是,假如有一个节点,如果一直调用该节点的next,最后会回到该节点,那么这个链表就是带环的。

环形链表的性质分析

假如有个cur指针从头开始遍历链表,如果这个链表不是环形链表,那么这个cur指针会遍历至NULL指针处
在这里插入图片描述
那么让一个指针从头开始遍历整个链表,如果这个指针到了NULL,就说明这个链表,不是环形链表。

	while (cur)
	{
		cur = cur->next;
	}
	return false;

但是如果这个链表是环形链表该如何证明呢?因为环形链表中是不在空节点的(NULL)。如果cur一直遍历,那么迭代就会进入死循环
在这里插入图片描述

解决思路就是在环形链表当中加入一个标志指针,让这个指针处于环形处。
在这里插入图片描述
这样子让cur指针继续遍历链表,最后一定会遇上flag指针,证明这个链表是环形链表

快慢指针法

那么问题来了,如何让flag指针处于环内呢?因为如果计算机知道flag处于什么位置是环内,我又何必写一大堆代码证明这个链表是环形链表呢?而且如果这个链表不带环,那么flag又应该在什么位置呢?

为了解决这个问题,我们可以设置两个指针指向第一个节点,一个是快指针fast,一个是慢指针slow,让快指针一次递进多个节点,而慢指针依次递进一个节点,让这个操作进行循环。

如此操作,会发生两种情况

情况1,链表为非带环链表,fast指针来到空节点处(NULL),返回false

在这里插入图片描述
情况2,链表为带环链表,fast指针会一直循环遍历环形链表。slow一定会进入环内。
在这里插入图片描述
fast会在链表内循环遍历,所以fast有可能会和slow重合,如果fast和slow重合了,就说明这个链表是环形链表。

指针的追及相遇问题

通过前面前面分析可知,如果该链表是环形链表,那么快指针就有可能在环内与慢指针相遇,那么会不会发生快慢指针不会相遇的情况呢?

首先快指针一定是比慢指针移动更快的,我们假设快指针每次移动两个节点,慢指针每次移动一个节点。

我们假设现在有一个环形链表,这个链表的入口点为点P。

设慢指针来到入口p时,快指针与慢指针的距离为N

在这里插入图片描述
慢指针走一步,快指针会走两步,因此这两个指针的距离会随着执行次数,每次减一(慢指针的走1步,快指针的会走2步,那么快指针相距慢指针就近了一步)。

次数距离
0N
1N-1
2N-2
依此类推
N-22
N-11
N0

可以发现,如果快指针走两步,慢指针走一步,那么这两个指针一定会在环中相遇。

那么如果快指针一次移动三个节点,慢指针一次移动一个节点,我们能得出什么样的结论呢?

还是假设当慢指针到达入口点距离快指针的距离为N
在这里插入图片描述
当慢指针与快指针的距离N为偶数时

次数 距离
0N
1N-2
2N-4
依次类推
N/2-12
N/20

当N为偶数时,快慢指针会相遇

当快指针与慢指针之间的距离为奇数时

次数 距离
0N
1N-2
2N-4
依次类推
N/2-11
N/2-1

可以发现快指针会越过慢指针,此时快指针会比慢指针多一个节点左右的距离,快指针需要再次遍历整个环形链表,直到与慢指针相遇。
在这里插入图片描述
设环形链表的周长为C,那么此时快指针与慢指针的距离为C-1.

当C为奇数时,C-1为偶数

那么程序的运行次数与快慢指针的距离关系为

次数 距离
0C-1
1C-3
2C-5
依次类推
(C-1)/2-12
(C-1)/20

由此推出,当N为奇数,C为奇数时,快指针最后会追上慢指针。

当C为偶数时,C-1为奇数

次数 距离
0C-1
1C-3
2C-5
依次类推
(C-1)/2-11
(C-1)/2-1

可以发现快指针和慢指针的距离在这一次追及之后,快慢指针的距离又回到了C-1。所以当N为奇数,C为偶数(C-1为奇数)时,快指针走三个节点,慢指针走1个节点的方式会永远不会相遇。

综上所述,如果我们想用快慢指针相遇的方式证明环形链表,最好的方法是让快指针一次后进两个节点,而慢指针一次后进一个节点。

当快指针后进多个(大于等于2)的节点时,有可能会出现快慢指针永远无法相遇的情况。比如当快指针后进3个节点时,如果此时N为奇数,C为偶数时,快指针永远无法与慢指针相遇,从而导致死循环的出现

解题代码如下:

bool hasCycle(struct ListNode *head) {
    if(head==NULL)
    return false;
    struct ListNode*slow=head;
    struct ListNode*fast=head->next;

    while(fast)
    {
        if(fast->next==NULL)
        return false;

        fast=fast->next->next;
        slow=slow->next;

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

环形链表(2)

在这里插入图片描述
这是前面环形链表的变形体,这个OJ的要求是这样的:假设这是一个环形链表,那么就要找到这个链表的入口节点,并将这个节点返回。如果是非环形链表,则返回NULL指针。

首先,我们将这个问题的实现分为两个部分,第一、我们要先确定这是一个环形链表,然后,我们求出这个环形链表的入口点。

确定环形链表的方法已经说明过了,现在要思考的是如何找到这个入口点。

我们首先来思考一下快慢指针的位移关系,已知,快指针的速度是慢指针的两倍,因此当慢指针来到入口点L时,快指针已经移动2L了。

我们假设从链表头到入口点的距离为L,从入口点到达相遇点的距离为N,环形链表的周长为C。
在这里插入图片描述

如果L>C。假如slow移动了L的距离来到入口点,可以知道fast移动距离为2L,在圈内循环了x圈(x至少为1)
当slow来到相遇点时,那么slow移动的距离是L+N,而fast移动的距离为L+N+(x+1)C。

如果L<C。假如slow移动了L的距离来到入口点,可以知道fast移动距离为2L,在圈内循环了0圈
当slow来到相遇点时,那么slow移动的距离是L+N,而fast移动的距离为L+N+C。

根据fast的位移是slow的两倍可以得出:
当L>C时,2(L+N)=L+N+(x+1)C。
当L<C时,2(L+N)=L+N+C。

可以合并成一个公式:
2(L+N)=L+N+yC。(y>=1).

合并同类项得L=yC-N。
我们可以图中明显的看出一个关系
在这里插入图片描述

如果一个指针从相遇点移动YC-N个节点时,会来到入口点。而且一个指针从链表头开始移动L位时,回来到入口点。
并且L=yC-N。

可以得出,如果让一个指针从链表头开始移动,一个指针从相遇点开始移动。这两个指针会在入口点相遇。

代码如下:

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

    while(fast)
    {
        if(fast->next==NULL)
        return NULL;
        fast=fast->next->next;
        slow=slow->next;

        if(fast==slow)
        {
            struct ListNode*meet=slow;

            while(meet!=head)
            {
                meet=meet->next;
                head=head->next;
            } 
            return meet;
        }
    }
    return NULL;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SAP PP学习笔记- 豆知识01 - 怎么查询既存品目

SAP系统当中已经有哪些品目要怎么查询呢&#xff1f; 1&#xff0c;MM60 品目一览 这里可以输入Plant&#xff0c;然后可以查询该工厂的所有品目。 2&#xff0c;SE16 > MARA MARA 品目一般Data&#xff0c;存放的是品目基本信息。 如果要查询该品目属于哪个Plant&#x…

【研究生复试】计算机软件工程人工智能研究生复试——资料整理(速记版)——计算机网络

1、JAVA 2、计算机网络 3、计算机体系结构 4、数据库 5、计算机租场原理 6、软件工程 7、大数据 8、英文 自我介绍 2. 计算机网络 1. TCP如何解决丢包和乱序&#xff1f; 序列号&#xff1a;TCP所传送的每段数据都有标有序列号&#xff0c;避免乱序问题发送端确认应答、超时…

[01] Vue2学习准备

目录 vue理解创建实例插值表达式 {{}}响应式特性 vue理解 Vue.js 是一套构建用户界面的渐进式框架。 Vue 只关注视图层&#xff0c; 采用自底向上增量开发的设计。 Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 创建实例 准备容器 <div id…

问题:如果要编辑建好的建筑和空间,需要在分级按钮( )和细分操作按钮楼层下,才能选中建筑物和空间; #微信#媒体#其他

问题&#xff1a;如果要编辑建好的建筑和空间&#xff0c;需要在分级按钮&#xff08; &#xff09;和细分操作按钮楼层下&#xff0c;才能选中建筑物和空间&#xff1b; A、楼层 B、规划图 C、全景 D、建筑物 参考答案如图所示

JVM(3)高级篇

1 GraalVM 1.1 什么是GraalVM GraalVM是Oracle官方推出的一款高性能JDK&#xff0c;使用它享受比OpenJDK或者OracleJDK更好的性能。 GraalVM的官方网址&#xff1a;https://www.graalvm.org/ 官方标语&#xff1a;Build faster, smaller, leaner applications。 更低的CPU、内…

Midjourney提示词风格调试测评

在Midjourney中提示词及风格参数的变化无疑会对最终的作品产生影响&#xff0c;那影响具体有多大&#xff1f;今天我我们将通过一个示例进行探究。 示例提示词&#xff1a; 计算机代码海洋中的黄色折纸船&#xff08;图像下方&#xff09;风格参考:金色长发的女人&#xff0c…

vue3-应用规模化-路由和状态

客户端 vs. 服务端路由 服务端路由指的是服务器根据用户访问的 URL 路径返回不同的响应结果。当我们在一个传统的服务端渲染的 web 应用中点击一个链接时&#xff0c;浏览器会从服务端获得全新的 HTML&#xff0c;然后重新加载整个页面。 然而&#xff0c;在单页面应用中&…

电商+支付双系统项目------简介

电商支付双系统项目是一个综合性的项目&#xff0c;旨在建立一个完善的电商系统和独立的支付系统&#xff0c;以满足中国日益增长的电商交易需求并提供多样化、安全可靠的支付方式。随着中国电商行业的快速发展&#xff0c;电商平台需要具备高效、可靠的功能&#xff0c;而独立…

中国比特币矿工的新根据地:埃塞俄比亚

原文标题&#xff1a;《Chinese Bitcoin Miners Find a New Crypto Haven in Ethiopia》 撰文&#xff1a;David Pan、Fasika Tadesse&#xff0c;彭博社 编译&#xff1a;Carl&#xff0c;Techub News 中国比特币矿工的新根据地&#xff1a;埃塞俄比亚 去年春天&#xff0c…

蓝桥杯电子类单片机提升三——NE555

目录 单片机资源数据包_2023 一、NE555和定时器工作模式 1.NE555的介绍 2.定时器的计数模式 二、NE555频率读取代码的实现 1.定时器0初始化 2.通过读取TH0和TL0来读取频率 3.通过中断读取频率 三、完整代码演示 通过读取TH0和TL0来读取频率 main.c 通过中断读取频…

领导力提升,才是高绩效的关键

作为企业的CEO或团队管理者&#xff0c;在日常的团队管理工作中无论是领导力还是执行力&#xff0c;都是非常重要的。在领导力的提升方面&#xff0c;我们可以通过一整套方案来进行&#xff0c;包括如何设定目标&#xff0c;动机刺激、任务拆解、鼓励参与、责任承担、建立制度、…

NLP_ChatGPT的RLHF实战

文章目录 介绍小结 介绍 ChatGPT 之所以成为ChatGPT&#xff0c;基于人类反馈的强化学习是其中重要的一环。而ChatGPT 的训练工程称得上是复杂而又神秘的&#xff0c;迄今为止&#xff0c;OpenAl也没有开源它的训练及调优的细节。 从 OpenAl已经公开的一部分信息推知&#xff…

STM32——OLED菜单(二级菜单)

文章目录 一.补充二. 二级菜单代码 简介&#xff1a;首先在我的51 I2C里面有OLED详细讲解&#xff0c;本期代码从51OLED基础上移植过来的&#xff0c;可以先看完那篇文章&#xff0c;在看这个&#xff0c;然后按键我是用的定时器扫描不会堵塞程序,可以翻开我的文章有单独的定时…

大模型专题:2023爱分析·大模型厂商全景报告

今天分享的是大模型系列深度研究报告&#xff1a;《大模型专题&#xff1a;2023爱分析大模型厂商全景报告》。 &#xff08;报告出品方&#xff1a;爱分析&#xff09; 报告共计&#xff1a;80页 研究范围定义 大模型是指通过在海量数据上依托强大算力资源进行训练后能完成…

java8-使用流-2

筛选各异的元素 流还支持一个叫作aistinct的方法&#xff0c;它会返回一个元素各异(根据流所生成元素的hashcode和eguals方法实现)的流。例如&#xff0c;以下代码会筛选出列表中所有的偶数&#xff0c;并确保没有重复。图5-2直观地显示了这个过程。 List<Integer>number…

Redis面试题整理(持续更新)

1. 缓存穿透&#xff1f; 缓存穿透是指查询一个一定不存在的数据&#xff0c;如果从存储层查不到数据则不写入缓存&#xff0c;这将导致这个不存在的数据每次请求都要到 DB 去查询&#xff0c;可能导致DB挂掉&#xff0c;这种情况大概率是遭到了攻击。 解决方案&#xff1a; …

【C++】:位图、布隆过滤器、哈希分割

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下位图、布隆过滤器、哈希分割&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精…

【JAVA-Day90】Java如何主动发起Http、Https请求?

Java如何主动发起Http、Https请求&#xff1f; Java如何主动发起Http、Https请求&#xff1f;摘要引言一、什么是Http和Https二、如何发起Http请求三、如何发起Https请求四、Http请求的状态码和数据解析五、Http请求面试题六、总结参考资料未来展望 博主 默语带您 Go to New Wo…

公需课考试怎么搜题找答案?推荐你使用这5个公众号和工具 #知识分享#其他#知识分享

大学生必备&#xff0c;这条笔记大数据一定定要推给刚上大学的学弟学妹&#xff01;&#xff01; 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试…

Android 回退页面不是上个页面

问题 Android 回退页面不是上个页面 详细问题 笔者进行Android 开发&#xff0c;点击返回上一层&#xff0c;显示页面不是上个页面&#xff0c;而是之前的某个页面 页面跳转代码 private void navigateToActivity(Context context, Class<?> targetActivityClass) {I…