剑指offer JZ23 链表中环的入口结点

news2024/11/15 17:48:46

问题描述:

        给定一个长度为n的链表,首先判断其是否有环,然后找到环的入口。

要求:空间复杂度 O(1),时间复杂度 O(n)。

思路:

1. 投机一点的做法

从头遍历链表,如果有环,那么有些节点一定会被重复访问,那么只需返回第一个重复的节点即可。java中用set或者map都可以实现,并且方法是现成的,所以代码很简单。

代码实现:

public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        HashSet<ListNode> set = new HashSet<>();
        while (pHead != null) {
            if (set.contains(pHead)) {
                return pHead;
            }
            set.add(pHead);
            pHead = pHead.next;
        }
        return null;
    }
}

2.双指针(推荐掌握)

        设置快慢指针。

        分析问题,我们发现,这道题需解决两个问题,①判断链表是否有环;②在有环的链表中找到环的入口。

对于①:如果无环,那链表的最后一定是指向null,反之,则快慢指针会循环遍历环的部分,会相遇。

②:此时我们已经确定了链表有环,此时我们需要推导一下。我们让快指针fast每次前进两个节点,慢指针slow每次前进1个节点,fast先进入环,并在里面循环,随后slow进入环,最终两者会在环内某个节点处相遇。

如下图,我们假设fast在环内走了n圈,slow走了m圈,然后相遇,而进入环之前的距离为x,环入口到相遇位置的距离为y,相遇位置到环入口的另一段距离为z;那么在这个过程中,快指针一共走了x+n*(y+z)+y,慢指针共走了x+m*(y+z)+y,而相同的时间,fast是slow 速度的2倍,所以距离也是2倍,故:x+n*(y+z)+y=2(x+m*(y+z)+y),推导得出(其中N=n-2m,为一个整数)

x + y =N*\left ( y+z \right )\Rightarrow x=N*\left ( y+z \right ) - y

        因为x+y是从头到相遇节点的长度,y+z是环的长度,由式子得出,进入环之前的距离x为一个整数倍的环的长度减去一个由入环节点到相遇节点的距离。也就是说,如果以相同的速度,让两个指针,一个从头开始遍历到相遇节点,一个从相遇节点在环中遍历,最后到相遇的节点走的是相同的距离,而因为此时速度相同,所以其中y这个距离,就是重复走的距离,那么他们第一次相遇的点就是环的入口节点了。

代码:

public class Solution {
    
    //先判断有没有环,有环则返回相遇的节点
    public ListNode hasCycle(ListNode pHead){
        if (pHead == null) return null;

        //快慢指针
        ListNode fast = pHead;
        ListNode slow = pHead;
        //若无环,则fast肯定先到链表尾
        while (fast != null && fast.next != null){
            //fast移动两步
            fast = fast.next.next;
            //slow移动一步
            slow = slow.next;
            //相遇,则表明有环,并返回相遇的位置
            if (fast == slow)
                return slow;
        }
        //无环
        return null;
    }
    public ListNode EntryNodeOfLoop(ListNode pHead) {

        ListNode slow = hasCycle(pHead);
        //无环
        if (slow == null)
            return null;
        //有环,则快指针返回链表头
        ListNode fast = pHead;
        //再次相遇则为入口
        while (fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

思考:

知识点:双指针指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个指针(特殊情况甚至可以多个),两个指针或是同方向访问两个链表、或是同方向访问一个链表(快慢指针)、或是相反方向扫描(对撞指针),从而达到我们需要的目的。

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

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

相关文章

Docker初识(Docker技术集群与应用)

一、基础设施即服务 IaaS&#xff08;Infrastructure as a Service&#xff09; eg&#xff1a;购买的云服务器&#xff0c;就是IaaS 提供给客户的服务是对所有设施的利用&#xff0c;包括处理、存储、网络和其他基本的计算资源。客户能够部署和运行任意软件&#xff0c;包括…

LLM大模型学习:探索LLM的精髓-理解Prompts概念与LangChain快速应用技巧”

LLM 中什么是Prompts&#xff1f;如何使用LangChain 快速实现Prompts 一 Prompt是一种基于自然语言处理的交互方式&#xff0c;它通过机器对自然语言的解析&#xff0c;实现用户与机器之间的沟通。 Prompt主要实现方式是通过建立相应的语料库和语义解析模型&#xff0c;来将自…

《A Few Useful Things to Know about Machine Learning》论文导读

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl机器学习作为人工智能领域的重要分支,近年来得到了广泛的关注和应用。Pedro Domingos的经典论文《A Few Useful Things to Know about Machine Learning》为我们提供了对机器学习深入且全面的理解…

Java方法的定义,即“函数“的定义!

方法的作用 提高代码的复用性&#xff0c;写一次&#xff0c;你需要的时候直接去调用即可。 定义一个函数方法 [修饰符1 修饰符2 ...] 返回值类型 方法名(形参){Java语句&#xff1b;... ... ... }初次接触方法的举例&#xff1a;两个整数的求和方法 根据上面的例子我们来分…

虚拟机扩充磁盘空间

本人使用的VMware首先关闭虚拟机在设置中进行磁盘扩展&#xff0c;输入扩展的空间 具体扩展步骤 fdisk /dev/sda输入p&#xff0c;查看分区情况输入n新建一个分区&#xff0c;还有之后两步&#xff0c;全部默认输入w保存分区fdisk -l使用vgdisplay查看卷组信息&#xff1a;vgdi…

动手学深度学习(pytorch)学习记录26-卷积神经网路(LeNet)[学习记录]

目录 LeNet模型训练 LeNet 总体来看&#xff0c;LeNet&#xff08;LeNet-5&#xff09;由两个部分组成&#xff1a; 卷积编码器&#xff1a;由两个卷积层组成; 全连接层密集块&#xff1a;由三个全连接层组成。 每个卷积块中的基本单元是一个卷积层、一个sigmoid激活函数和平均…

Docker 清理和查看镜像与容器占用情况

查看容器占用磁盘大小 docker system df 查看单个image、container大小&#xff1a; docker system df -v 清理所有废弃镜像与Build Cache docker system prune -a

【解决内存泄漏的问题】 Qt 框架中的父子对象关系会自动管理内存,父对象会在其销毁时自动销毁所有子对象。

修改前的代码 这段代码可能会出现内存泄漏问题&#xff0c;主要原因是构造函数中创建的 LoginDialog 和 RegisterDialog 对象未在合适的地方被正确释放。具体分析如下&#xff1a; 1. 构造函数中的问题 _login_dlg new LoginDialog(); setCentralWidget(_login_dlg); _login…

【北京迅为】《STM32MP157开发板使用手册》- 第十二章 编译Linux内核

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

运算放大器中的反馈

运算放大器中的反馈&#xff1a;原理、类型与应用 运算放大器&#xff08;Operational Amplifier, 简称Op-Amp&#xff09;是现代电子电路中的重要组成部分&#xff0c;被广泛应用于信号处理、放大、滤波等场合。而反馈技术则是运算放大器电路的核心之一&#xff0c;直接影响其…

代码随想录算法训练营第二十二天| 491. 递增子序列、46. 全排列、47. 全排列Ⅱ

今日内容 Leetcode. 491 递增子序列Leetcode. 46 全排列Leetcode. 47 全排列Ⅱ Leetcode. 491 递增子序列 文章链接&#xff1a;代码随想录 (programmercarl.com) 题目链接&#xff1a;491. 非递减子序列 - 力扣&#xff08;LeetCode&#xff09; 本题也是一个子集问题&#…

【AI绘画】Midjourney后置指令--seed、--tile、--q、--chaos、--w、--no详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;Midjourney后置指令--seed测试1测试2如何获取未指定种子图片的随机种子注意点 &#x1f4af;Midjourney后置指令--tile测试 &#x1f4af;Midjourney后置指令--q(or-…

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI&#xff08;简称 RVC&#xff09;模型是一个基于 VITS&#xff08;Variational Inference with adversarial learning for end-to-end Text-to-Speech&#xff09;的简单易用的语音转换框架。 具有以下特点 简单易用&a…

chrome浏览器如何设置自动播放音视频

使用场景&#xff1a; 有些场景需要打开页面后&#xff0c;自动播放视频或者视频流&#xff0c;这时候发现无法播放&#xff0c;打开浏览器控制台发现有下面的错误提示&#xff1a;NotAllowedError: play() failed because the user didnt interact with the document first 。…

顶级出图效果!免费在线使用FLux.1 模型,5s出图无限制!

最近发现一个可以在线免费使用 FLux.1 模型 生成图片的AI工具。 先看效果图&#xff1a; 工具不需要登录即可使用&#xff0c;目前还是完全免费的&#xff0c;国内可以直接使用。 在提示词输入框直接输入提示词即可&#xff0c;选择图片比例之后&#xff0c;直接生图。 出图的…

安全运营之浅谈SIEM告警疲劳

闲谈&#xff1a; 刚开始学习SIEM、态势感知这类产品的时&#xff0c;翻阅老外们的文章总是谈什么真阳性&#xff0c;假阳性告警、告警疲劳&#xff0c;当时在国内资料中没找到很合理的解释&#xff0c;慢慢就淡忘这件事了。随着慢慢深入工作&#xff0c;感觉大概理解了这些概念…

‌技术人必看!如何科学规划,从需求出发打造完美技术方案

引言 在互联网架构师的角色中&#xff0c;我们面临的挑战不仅仅是编写代码&#xff0c;更重要的是深入理解需求、设计系统&#xff0c;并确保我们的解决方案能够稳定、高效地运行。本文将详细介绍从新需求提出到技术方案发布的全过程。 1. 理解现有需求和场景 在开始一个新的…

信息学奥赛初赛天天练-87-NOIP2014普及组-完善程序-矩阵、子矩阵、最大子矩阵和、前缀和、打擂台求最大值

1 完善程序 最大子矩阵和 给出 m行 n列的整数矩阵&#xff0c;求最大的子矩阵和(子矩阵不能为空)。 输入第一行包含两个整数 m和 n&#xff0c;即矩阵的行数和列数。之后 m行&#xff0c;每行 n个整数&#xff0c;描述整个矩阵。程序最终输出最大的子矩阵和。 &#xff08;最…

SAP中mmpv自动过账—附带源码

想省事儿的直接拖到后面查看代码 思路分析 实现逻辑:初版 前台测试:选择屏幕确认公司代码。必要情况手动开账勾选前台执行按钮 1.1去marv表找公司代码的当前账期,简单运算获取下一个账期。1.2执行bdc,模拟前台手动开账期1.3执行的必要信息存日志表。例:修改人(开账期的人…

FastAPI 进阶:使用 BackgroundTasks 处理长时间运行的任务

在 FastAPI 中&#xff0c;BackgroundTasks 是一个功能&#xff0c;它允许你在发送响应给客户端之后执行后台任务。这些任务对于不需要客户端等待的操作非常有用&#xff0c;比如发送电子邮件通知或处理数据。然而&#xff0c;当服务器重启时&#xff0c;由于 BackgroundTasks …