【算法题解】11. 判断链表是否有环,并返回入环节点

news2024/11/24 6:34:47

文章目录

    • 题目
    • 解法一:循环标记
      • Java代码实现
      • Go 代码实现
      • 复杂度分析
    • 解法二:快慢指针
      • Java 代码实现
      • Go 代码实现
      • 复杂度分析

这是一道 中等难度 的题,是 判断链表是否有环 的扩展,在有环的情况下返回入环节点, 依然是两种解法。题目来自:leetcode

题目

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
不允许修改 链表。

示例 1:
判断链表是否有环,并返回入环节点

输入:head = [3,2,0,-4], pos = 1 
输出:返回索引为 1 的链表节点 
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:
判断链表是否有环,并返回入环节点

输入:head = [1,2], pos = 0 
输出:返回索引为 0 的链表节点 
解释:链表中有一个环,其尾部连接到第一个节点。 

示例 3:
判断链表是否有环,并返回入环节点

输入:head = [1], pos = -1 
输出:返回 null 
解释:链表中没有环。 

提示:
● 链表中节点的数目范围在范围 [ 0 , 1 0 4 ] [0, 10^4] [0,104]
− 1 0 5 < = N o d e . v a l < = 10 5 5 -10^5 <= Node.val <= 105^5 105<=Node.val<=1055
pos 的值为 -1 或者链表中的一个有效索引

进阶: 你是否可以使用 O ( 1 ) O(1) O(1) 空间解决此题?

解法一:循环标记

循环遍历每一个节点并标记为已访问,返回第一次遍历到的已访问节点,否则最后返回 null

Java代码实现

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
 
        Set<ListNode> visited = new HashSet<>();
        while(head != null){
            if(visited.contains(head)){
                return head;
            }
            visited.add(head);
            head = head.next;
        }
        return null;

    }
}

Go 代码实现

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {

    visited := make(map[*ListNode]bool)
    for head != nil {
        if visited[head]{
            return head;
        }
        visited[head] = true
        head = head.Next
    }
    return nil

}

复杂度分析

时间复杂度 O ( N ) O(N) O(N):需要访问链表中的每一个节点,时间复杂度为链表长度n
空间复杂度 O ( N ) O(N) O(N):需要记录每个访问过的节点,空间复杂度为链表的长度n

解法二:快慢指针

快指针每次走 2 步, 慢指针每次走 1 步,若 快慢指针 能够相遇说明链表有环,但是第一次相遇的点并不一定是入环点,如下所示:
判断链表是否有环,并返回入环节点
相遇点 7 并不是入口点 4
在判断链表是否有环,并返回入环节点

那么怎么找到入环点呢?假如入环点前有 a 个节点,环上有 b 个节点,第一次相遇时快指针走了 f 步,慢指针走了 s 步。
判断链表是否有环,并返回入环节点

由以上假设可以得知:

  1. f = 2s;(快指针走的步数是慢指针的 2 倍)
  2. f - s = nb;(快指针比慢指针多走了 n 个环的步数,然后相遇)
    即第一次相遇时,慢指针走了 nb 步,快指针走了 2nb 步。

第一次相遇的点还需要走多少步到达入环点?
判断链表是否有环,并返回入环节点
因为到达入环点的步数为:a + nb, 其中 n >= 0。现在 慢指针 已经走了 nb 步,那么再走 a 步必定可以到达入环点,但是我们并不知道 a 是多少。

判断链表是否有环,并返回入环节点
我们可以换个思路,此时可以把 快指针 重新指到起始点 head,即 快慢指针 到达入环点为步数都是 a , 那么当 快慢指针 再次相遇的地方就是入环点了。

完整流程如下:
判断链表是否有环,并返回入环节点

Java 代码实现

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {

        ListNode fast = head, slow = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            // 第一次相遇
            if(slow == fast){
                fast = head;
                while(fast != slow){
                    fast = fast.next;
                    slow = slow.next;
                }
                // 第二次相遇
                return fast;
            } 
            
        }
        return null;
        
    }
}

Go 代码实现

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {

    fast, slow := head, head
    for fast != nil && fast.Next != nil {
        fast, slow = fast.Next.Next, slow.Next
        if(slow == fast){
            fast = head
            for fast != slow {
                fast, slow = fast.Next, slow.Next
            }
            return fast
        }
    }
    return nil

}

复杂度分析

时间复杂度 O ( N ) O(N) O(N):时间复杂度为慢指针所走的步数为 nb + a -> (n - 1)b + (a + b) -> (n - 1)b + 链表的总节点数 ,因为 nb 都是是常数,所以复杂度近似为 O ( N ) O(N) O(N)
空间复杂度 O ( 1 ) O(1) O(1):只需要记录快慢指针的位置,为常数空间复杂度。

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

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

相关文章

Disney 流媒体广告 Flink 的应用实践

摘要&#xff1a;本文整理自 Disney 广告智能执行总监郝又超、Disney 广告智能实时计算负责人李丁哲&#xff0c;在 FFA 主会场的分享。本篇内容主要分为四个部分&#xff1a;Disney 流媒体广告与实时应用业务场景实现实时平台构建未来展望Tips&#xff1a;点击「阅读原文」查看…

kafka.2 集群搭建

文章目录1.启动kakfa自带的zk2.启动kafka集群3.查看zookeeper的kafka节点信息启停kafka集群脚本创建主题增加分区模拟生产消费模拟消费组消费主题&#xff0c;查看offset1.启动kakfa自带的zk 参考&#xff1a;https://blog.csdn.net/justlpf/article/details/127261664?utm_m…

通俗易懂的java设计模式(7)-原型模式

1.什么是原型模式&#xff1f; 原型模式提供了一种创建对象的模式&#xff0c;它是指用原型实例创建对象的种类&#xff0c;并且通过拷贝这些原型&#xff0c;创建新的对象。用一个很生动形象的例子&#xff1a;孙悟空拔出一根猴毛&#xff0c;变出其他和自己一模一样的小孙悟…

Linux三剑客之Sed

目录 一、认识sed 二、使用sed 命令格式 常用选项options 地址定界 编辑命令command sed用法 常用选项&#xff1a; 地址界定演示 编辑命令command演示 sed高级编辑命令 一、认识sed sed 是一种流编辑器&#xff0c;它一次处理一行内容。处理时&#xff0c;把当前处理的行…

《Linux Shell脚本攻略》学习笔记-第九章

9.1 简介 计算机系统是由一组硬件及控制这些硬件的软件组成的。 Linux既提供了能够检查这些系统当前性能的交互式程序&#xff0c;也提供了用于记录一段时间内系统性能表现的模块。 9.2 监视磁盘使用情况 磁盘空间是一种有限的资源。 du和df命令可以报告磁盘使用情况&#xff0…

消息中间件如何选型 图解 Kafka vs RabbitMQ vs RocketMQ 的差异

综述 Kafka 采用拉取 ( Pull) 方式消费消息&#xff0c;吞吐量相对更高&#xff0c;适合海量数据收集与传递场景&#xff0c;例如日志采集和集中分析缺点 Kafka 单机超过 64 个队列/分区&#xff0c;Load 会发生明显的飙高现象&#xff0c;队列越多&#xff0c;load 越高&#…

linux基本功系列之chage命令实战

文章目录前言一. chage命令的介绍二. 常用案例示范1. 查看用户密码的有效期2. 设置密码的过期时间3. 设置账号的失效时间总结前言 前言&#x1f680;&#x1f680;&#x1f680; 想要学好Linux&#xff0c;命令是基本功&#xff0c;企业中常用的命令大约200多个&#xff0c;不管…

2023牛客寒假算法基础集训营1

题解 | #2023牛客寒假算法基础集训营1#_牛客博客 (nowcoder.net) //本人能力有限&#xff0c;以下只附上本人get到的题&#xff0c;其他参考以上链接或其他 A World Final? World Cup! (I) 链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 …

【自学Docker 】Docker top命令

Docker top命令 大纲 docker top教程 使用 docker top 命令可以用来查看 Docker 中运行的进程信息。docker top 命令后面的 CONTAINER 可以是容器 ID&#xff0c;或者是容器名。 docker top语法 haicoder(www.haicoder.net)# docker top [OPTIONS] CONTAINER [ps OPTIONS]案…

说话的三重复杂性

从0开始首先要有一个说话者&#xff0c;这个说话者说出来的话有三重有意。说话者想要表达的东西。文字本身的意义。倾听者所理解的意义。例子&#xff1a;说话者问&#xff1a;有女朋友吗&#xff1f;我们假设说话者要表达&#xff0c;如果还没&#xff0c;那么一起加班。文字本…

GIS入门进阶之017

一、网络分析 网络分析是ArcGIS提供的重要的空间分析功能&#xff0c;利用它可以模拟现实世界的网络问题。如从网络数据中寻找多个地点之间的最优路径&#xff0c;确定网络中资源的流动方向、资源配置和网络服务范围等。 网络是图论和运筹学中的一个数学模型&#xff0c;通常用…

【C#】封装.net framework函数库,并打包发布dll函数库到nuget服务器

作者&#xff1a;小5聊 简介&#xff1a;一只喜欢全栈方向的程序员&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff0c;尽绵薄之力答疑解惑&#xff01; 1、Nuget函数库管理工具 1.1、什么是Nuget Nuget是一个.NET平台下的开源的项目&#xff0c;它是Visual Stu…

电脑怎么设置定时关机?分享2个简单操作!

随着互联网时代的发展&#xff0c;越来越多人使用电脑。使用过程中&#xff0c;有时会产生很多疑惑&#xff0c;其中有朋友问小编&#xff1a;电脑怎么设置定时关机&#xff1f;其实Windows系统设置关机很简单&#xff0c;主要有下面两个方法&#xff01; 演示机型&#xff1a;…

【学习打卡 Free-Excel 】Task1~2 数据源何而来_数据格式

free-excel 文章目录free-excel1 数据基本知识工作簿与工作表xls和xlsx单元格行列导入数据从文件导入数据从网页导入数据&#xff1a;中文编码&#xff1a;2 表格单元格数据类型excel错误提示数据统一添加符号数值转文本、文本转数值资源链接 Free excel_文字版Free excel&…

系分 - 案例分析 - 数据库设计(基本)

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录系分 - 案例分析 - 数据库设计&#xff08;基本&#xff09;数据库基础数据库设计规范化&#xff08;范式&#xff09;数据库事务并发控制典型例题题目描述参考答案数据库安全性技术视图物化视图存储过程触…

【练习】Day07

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录一、选择二、编程1. 不同路径2. 三角形最小路径和 [重点理解&#xff01;&#xff01;]答案1. 选择2. 编程普通小孩也要热爱生活&#xff01; 一、选择 以下关于 Servlet 生命周期说法错误的是 ( ) A: Servlet 容器…

解构模块化区块链

干货&#xff1a;解构模块化区块链 在可扩展性方面&#xff0c;模块化区块链是区块链设计的最新范式。 模块化的概念起源于Layer1区块链Celestia&#xff0c;现在这个概念也逐渐被更多的人所关注&#xff0c;还有人甚至提出”模块化区块链将定义Web3创新的下一个十年“的口号…

java.sql.SQLException: ORA-28001: the password has expired

1、找到SQL Plus 运行 2、登录 请输入户名: sys as sysdba 输入口令&#xff1a;&#xff08;sys用户的密码&#xff09;3、以dba角色登入 SQL >connect as sysdba; 请输入户名: sys as sysdba 输入口令&#xff1a;&#xff08;sys用户的密码&#xff09;4、修改密码 SQ…

Flink:FlinkSql解析嵌套Json

日常开发中都是用的简便json格式&#xff0c;但是偶尔也会遇到嵌套json的时候&#xff0c;因此在用flinksql的时候就有点麻烦&#xff0c;下面用简单例子简单定义处理下 1&#xff0c;数据是网上摘抄&#xff0c;但包含里常用的大部分格式 { "afterColumns": {…

SpringBoot集成Elasticsearch7.4 实战(一)

在网上已经有好多关于Elasticsearch的介绍&#xff0c;就不在翻来覆去讲一些基本概念&#xff0c;大家感兴趣的可以自己去找一些资料巩固下。这次只为了顾及众多首次接触Elasticsearch&#xff0c;案例都讲的很浅显&#xff0c;还有就是受个人能力所限&#xff0c;各位读者发现…