带环链表找入环结点及结论证明

news2024/11/27 18:31:18

文章目录

  • 前言
  • 1.带环链表
    • 1.1 带环链表介绍
    • 1.2 判断链表是否带环代码实现
    • 1.4 入环结点相关问题
      • 1.4.1 结论证明
      • 1.4.2 找入环结点代码实现
        • 1.4.2.1 代码实现1
        • 1.4.2.2 代码实现2
  • 总结


前言

1.带环链表

1.1 带环链表介绍

如下图中题目所述,带环结点尾结点的next指针域存储的可能是链表中任一结点的地址,遍历链表的时候就会死循环。

1.2 判断链表是否带环代码实现

141.环形链表(题目链接)
在这里插入图片描述
(截取部分题目描述)

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

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

}

1.4 入环结点相关问题

142.环形链表 II‌
在这里插入图片描述

1.4.1 结论证明

带环结点有一个经典的结论,即从快慢指针相遇点和第一个结点分别开始同步走,会在入环结点相遇。

我们假设两个指针fast, slow分别往前走,fast每次走两步,slow每次走一步,当fast入环的时候,slow大概在L/2的位置;接着,fast开始在环内不断的绕圈,当slow入环的时候,fast与slow的相对位置可能是0,1,2,3,…,C-1,因为fast走得快,所以此时转变为追击问题,fast追击slow,假设二者相对位置差N个结点,那么0=<N<=C-1.
fast每走一次,与slow的距离-1,那么走N次也就追上了,记录此时位置为meet,即相遇结点。
因为二者一直都在走,所以fast走的距离是slow的两倍。
fast走的距离为:L+X+C* n(n为正整数,因为slow走的是L+X,fast走的一定比slow快;这个n是相遇之前,fast走L+X,还走了n圈)
slow走的距离为:L+X
也即L+X+C* n=2(L+X),即L=C* n-X
我们结合下图来看上式的实际意义,让两个指针分别从相遇点和起始结点开始同时每次走一步,从头结点开始的指针走L步走到入环结点,从相遇结点开始走的指针绕环n-1圈后,再走(C-X)步到达入环结点,即从快慢指针相遇点和第一个结点分别开始同步走,会在入环结点相遇
在这里插入图片描述
在某位学长面试的时候,遇到过这样的问题:

  1. 带环链表怎么找入环结点?
  2. 为什么slow一次走一步,fast一次走2步,它们会相遇吗?会不会错过?
  3. 如果slow走1步,fast走X步(X>2),它们会相遇吗?会不会错过?以及,slow走2步的情况呢?
  4. 求环的长度(找到相遇结点后,再次从相遇结点走一周,就是环的长度)

问题1的代码实现如下,问题2已证明,我们来看问题3.
假设slow每次走1步,fast走3步,当fast入环的时候,slow大概在L/3的位置;接着,fast开始在环内不断的绕圈,当slow入环的时候,fast与slow的相对位置可能是0,1,2,3,…,C-1,因为fast走得快,所以此时转变为追击问题,fast追击slow,假设二者相对位置差N个结点,那么0=<N<=C-1.
fast每走一次,与slow的距离-2,如果N是偶数的话,那么走N/2次也就追上了;如果N是奇数的话,fast与slow的距离就逐渐变化,即N, N-3, N-5,…,1,-1.fast追击slow,那么fast与slow相对距离为-1,也就是fast超过slow,如下图所示。因为fast比slow走得快,那么此时开始新一轮的追击,如果C-1为偶数,可以追上;如果C-1为奇数,C-1是二者的相对距离,相当于N为奇数,最后二者相对距离是-1,也就是C-1,那么这样往复循环,永远追不上。
在这里插入图片描述
而fast走4步,slow每次走1步,我们考虑slow入环的时候二者相对距离N是3的倍数、N=3n+1、N=3n+2的情况;对于N=3n+1,我们要考虑C-1的情况,以此类推。
在这里插入图片描述

1.4.2 找入环结点代码实现

1.4.2.1 代码实现1
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* fast=head,*slow=head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;

        if(fast==slow)
        {
            struct ListNode* meet=slow;
            struct ListNode* start=head;
            while(meet!=start)
            {
                meet=meet->next;
                start=start->next;
            }
            return meet;
        }
    }
    return NULL;
}
1.4.2.2 代码实现2

第二种思路是,找到相遇结点,将该结点与后续结点断开,成为找两个链表的交点问题,该问题的代码在系列文章中,下面为链接,有兴趣的友友可以看一下。
链表OJ经典题目及思路总结(一)双指针
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode * tailA=headA,*tailB=headB;
    int lenA=1,lenB=1;
    while(tailA->next)
    {
        lenA++;
        tailA=tailA->next;
    }
    while(tailB->next)
    {
        lenB++;
        tailB=tailB->next;
    }
    if(tailA!=tailB)
        return NULL;
    int gap=abs(lenA-lenB);
    struct ListNode * longlist=headA,*shortlist=headB;
    if(lenA<lenB)
    {
        longlist=headB;
        shortlist=headA;
    }
    while(gap--)
        longlist=longlist->next;
    while(longlist!=shortlist)
    {
        longlist=longlist->next;
        shortlist=shortlist->next;
    }
    return longlist;
}
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* fast=head,*slow=head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;

        if(fast==slow)
        {
        	//转换成lt1与lt2求交点
            struct ListNode* lt1=slow->next;
            slow->next=NULL;
            struct ListNode* lt2=head;
            return getIntersectionNode(lt1,lt2);
        }
    }
    return NULL;
}

总结

带环结点在笔试面试中都有可能被考察到,并且带环结点找入环结点的思路以及衍生情况都是对逻辑思维很好的锻炼,希望读到这篇文章的你有所收获,下去可以尝试解题、掌握带环结点呀~
我不断奔跑,只为追上那个被寄予厚望的自己。

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

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

相关文章

Llama 3.2 视觉能力评估

Meta 发布了 Llama 3 模型的新版本&#xff1b;这次&#xff0c;有四种模型用于不同的目的&#xff1a;两个多模态模型&#xff0c;Llama 3.2 11B 和 90B&#xff0c;以及两个用于边缘设备的小型语言模型&#xff0c;1B 和 3B。 这些是 Meta AI 的首批多模态模型&#xff0c;基…

反射第二弹:用注册器动态注册(用自定义的注解标注的)策略,实现策略模式的设计

引言 曾经有人问我&#xff0c;假如有一个业务或者数据处理逻辑&#xff0c;会根据甲方客户繁杂的业务需求&#xff0c;而动态变化&#xff0c;该怎么处理&#xff0c;具体怎么实现&#xff1f; 将所有策略strategy都写出来&#xff0c;然后放入一个hashMap&#xff0c;根据不同…

VTK+其他布尔运算库

文章目录 一、vtkBool1.1 安装1.2 使用1.3 效果 二、CGAL 本文的主要内容&#xff1a;VTK内置的布尔运算类具有稳定性差、计算时间长等缺点&#xff0c;为了避免使用VTK内置的布尔运算&#xff0c;本文简单介绍了两个比较实用的库用于替代&#xff0c;主要涉及vtkBool和CGAL库的…

私域高效管理指南:提升用户粘性的高效法则

随着越来越多的品牌将目光投向私域流量&#xff0c;如何高效地管理这些用户并提升他们的粘性&#xff0c;成为了营销领域的重要课题。 下面&#xff0c;就分享一些私域高效管理的实用法则&#xff0c;帮助你在私域管理中游刃有余。 1、用户分层 对于新用户而言&#xff0c;他…

redhat7.7 linux 网络配置文件

一、为什么虚拟网卡配置文件是ens33 变更目录至网络脚本&#xff08;network-scripts&#xff09;文件夹&#xff0c;发现网络配置文件名称为“ifcfg-ens33” cd /etc/sysconfig/network-scripts ls扩展&#xff1a;“ifcfg-ens33”文件下面还有一个“ifcfg”前缀的文件&…

LabVIEW程序怎么解决 Bug?

在LabVIEW开发过程中&#xff0c;发现和解决程序中的Bug是确保系统稳定运行的关键环节。由于LabVIEW采用图形化编程方式&#xff0c;Bug的排查和处理与传统编程语言略有不同。以下是解决LabVIEW程序中Bug的常见方法和技巧&#xff0c;涵盖从问题发现到解决的多个步骤和角度&…

LabVIEW裂纹深度在线监测系统

随着铁路运输技术的快速发展&#xff0c;火车安全问题成为重中之重&#xff0c;尤其是轮面裂纹的检测和管理。裂纹的出现可能导致严重的列车事故&#xff0c;因此&#xff0c;建立可靠的在线监测系统&#xff0c;实时掌握裂纹情况&#xff0c;对保障铁路运输安全至关重要。 La…

快速构建 yolo 训练集 测试集

在机器学习工作流程中&#xff0c;数据处理是一个关键步骤。通常我们会使用不同的工具来标注数据&#xff0c;而每种工具都有其特定的格式。在这篇文章中&#xff0c;我们将展示如何从数据集中快速抽取样本&#xff0c;构建训练集和测试集。 YOLO简介 YOLO&#xff08;You On…

响应重定向

响应重定向 重定向也可以跳转servlet,也可以跳转页面 (功能与请求转发类似) 使用的方法: resp.sendRedirect("路径"); 测试: 改造登录Servlet,重定向到ListServlet ps: 可以跳转到ListServlet,但是因为请求域数据不能共享,可能会报错 特点 重定向是响应重定向,是浏…

大语言模型的微调方法_大语言模型六种微调方法,零基础入门到精通,收藏这一篇就够了

01 引言 自2018年BERT发布以来&#xff0c;“预训练微调”成为语言模型的通用范式。以ChatGPT为代表的大语言模型针对不同任务构造Prompt来训练&#xff0c;本质上仍然是预训练与微调的使用范式。千亿规模的参数微调需要大量算力&#xff0c;即使提供了预训练的基座模型&…

jQuery——文档的增删改

1、添加 / 替换元素 append&#xff08;content&#xff09;&#xff1a;向当前匹配的所有元素内部的最后插入指定内容prepend&#xff08;content&#xff09;&#xff1a;向当前匹配的所有元素内部的最前面插入指定内容before&#xff08;content&#xff09;&#xff1a;…

一、机器学习算法与实践_06迭代法和KMeans、线性回归、逻辑回归算法笔记

0 迭代法 迭代法不仅是机器学习、深度学习的核心&#xff0c;也是整个人工智能领域的重要概念&#xff0c;其对于算法的设计和实现至关重要 0.1 适合场景 对于不能一次搞定的问题&#xff0c;将其分成多步来解决&#xff0c;逐步逼近解决方案 0.2 典型应用 KMeans 聚类算法…

开放式耳机哪个品牌好?适合运动的开放式蓝牙耳机分享

如今&#xff0c;开放式耳机的购买量呈现出持续上升的趋势&#xff0c;变得越来越多。而随着人们对音频设备需求的不断提升以及对舒适佩戴体验和自然聆听感受的日益追求&#xff0c;开放式耳机也以其独特的优势逐渐走进大众的视野&#xff0c;成为众多消费者的新宠。 在各大电…

中文llama3仿openai api实战

课程介绍 本次课属于【大模型本地部署应用】&#xff0c;基于Chinese-LLaMA-Alpaca-3&#xff08;GitHub - ymcui/Chinese-LLaMA-Alpaca-3: 中文羊驼大模型三期项目 (Chinese Llama-3 LLMs) developed from Meta Llama 3&#xff09;项目&#xff0c;介绍如何封装一个私有的兼容…

谷歌收录批量查询,谷歌收录批量查询的简单方法

谷歌收录批量查询是网站管理员和SEO优化人员常见的需求&#xff0c;以下提供几种简单且高效的批量查询方法&#xff1a; 一、使用Google Search Console&#xff08;谷歌搜索控制台&#xff09; 注册并验证网站&#xff1a; 首先&#xff0c;确保你已经在Google Search Conso…

常用正则匹配中国手机号码

正则表达式匹配中国的手机号码。 我可以提供一些匹配中国手机号码的常用正则表达式: 仅匹配11位数字的手机号码:^1[3456789]\d{9}$匹配以1开头的11位数字手机号码:^1\d{10}$更宽松的匹配规则,允许0开头的手机号码:^(?:0|86|&#xff0b;?86)?1[3-9]\d{9}$ 这些正则表达式可…

Java基础知识总结(超详细整理)

Java基础知识总结&#xff08;超详细整理&#xff09; Java语言的特点 1.面向对象 面向对象(OOP)就是Java语言的基础&#xff0c;也是Java语言的重要特性。面向对象的概念&#xff1a;生活中的一切事物都可以被称之为对象&#xff0c;生活中随处可见的事物就是一个对象&#…

CMSIS-RTOS V2封装层专题视频,一期视频将常用配置和用法梳理清楚,适用于RTX5和FreeRTOS(2024-09-28)

【前言】 本期视频就一个任务&#xff0c;通过ARM官方的CMSIS RTOS文档&#xff0c;将常用配置和用法给大家梳理清楚。 对于初次使用CMSIS-RTOS的用户来说&#xff0c;通过梳理官方文档&#xff0c;可以系统的了解各种用法&#xff0c;方便大家再进一步的自学或者应用&#x…

【人工智能深度学习应用】妙策API最佳实践

功能概述 在文章创作过程中&#xff0c;用户可以借助AI妙策来辅助创作。AI妙策主要集中在聚合热点话题榜和平台话题榜两个方面。 具体功能 话题分析 AI妙策中的话题分析可以作为创作的灵感来源&#xff0c;通过网页视角选题、热门视角选题、时效视角选题、新颖视角选题&…

网站建设中,如何处理多语言版本?

在全球化的今天&#xff0c;网站多语言版本的处理成为了一项基本要求&#xff0c;尤其是对于面向国际用户的企业来说。以下是一些关于网站建设中如何处理多语言版本问题的建议&#xff1a; 使用URL国际化&#xff1a;通过在URL中添加语言代码&#xff08;如example.com/en/表示…