当前位置: 首页 > news >正文

LeetCode:环形链表II

文章收录于LeetCode专栏
LeetCode地址


环形链表II

题目

  给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回null。
  为了表示给定链表中的环,我们使用整数pos来表示链表尾连接到链表中的位置(索引从0开始)。如果pos是-1,则在该链表中没有环。
  注意,pos仅仅是用于标识环的情况,并不会作为参数传递到函数中。
  说明:不允许修改给定的链表。
  进阶:你是否可以使用 O(1) 空间解决此题?

  示例 1:
在这里插入图片描述

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

  示例 2:

在这里插入图片描述

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

  示例 3:

在这里插入图片描述

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

哈希表

算法思路

  借助Set数据结构不能存放重复数据的特性来判断链表是否有环,且记录当前节点,从而可在找到环路之后直接返回入环第一个节点。

编码

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

复杂度分析

  因为整个算法仅使用了一层循环遍历,所以其时间复杂度为O(n)。但是使用了一个HastSet辅助判断是否有重复节点,所以空间复杂度为O(1)。

快慢指针

算法思路

  我们也可以借助LeetCode 141题所讲的快慢指针来解答这个道题,首先定义一个快指针(每次走两步),再定义一个慢指针(每次走一步)。如果链表中存在环,慢指针一定会在第一轮与快指针相遇,我们假设环形链表一共有a+b个节点,其中a表示入环口之前的a个节点,b表示形成环的b个节点。
  假设快指针和慢指针第一次相遇时,快指针走了f步,慢指针走了s步:

  • 因为快指针每次走的步数是慢指针的两部,所以有f=2s;
  • 如果快指针要想在环内与慢指针相遇,那么快指针就必须得比慢指针多走n个环的长度,即n*b(b为环内节点个数);

  又假设慢指针在环内走了c步后与快指针相遇,那么这里就有:f = a + nb + c,s = a + c。结合前序条件f=2s,综合三个式子可得:

f = a + c + nb
s = a + c
f = 2s
将s = a + c 和 f = 2s代入f = a + c + nb求得
2s = s + nb => s = nb
再将s = nb代入s = a + c求得
nb = a + c => a = nb - c

  最后求得a = nb - c说明从链表起点还是走a步(即入环口),刚好等于环内一圈减去从入环口到相遇点的步数。有了这个结论之后,我们就可以在快慢指针第一次相遇时,将快指针重新指向链表头每次向前走一步,同时慢指针继续按照每次一步向前移动,当他们再次相遇的点,就是入环后的第一个节点。
在这里插入图片描述

编码

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/class Solution{public ListNode detectCycle(ListNode head){if(head == null){return null;}ListNode slow = head;ListNode fast = head;while(fast != null && fast.next != null){slow = slow.next;fast = fast.next.next;if(slow == fast){fast = head;while(fast != slow){fast = fast.next;slow = slow.next;}return fast;}}return null;}}

复杂度分析

  因为整个算法仅使用了一层循环遍历,所以其时间复杂度为O(n),并且没有使用任何额外内存空间所以空间复杂度为O(1)。


一键三连,让我的信心像气球一样膨胀!

相关文章:

  • Python | 平均绩点
  • Diffle-Hellman Key Exchange密钥交换
  • java面试题及答案2024,java2024最新面试题及答案(之一)
  • 【面试题】Node.js高频面试题
  • Android handler 一次通关
  • Go Modules 使用
  • 使用system verilog进行流水灯和VGA打印字符
  • CentOS 7基础操作01_安装CentOS 7操作系统
  • 【C语言】动态内存管理
  • 外星人Alienware m16R1 原厂Windows11系统 oem系统
  • 16、matlab求导、求偏导、求定积分、不定积分、数值积分和数值二重积分
  • 数据挖掘 | 实验三 决策树分类算法
  • 深入理解Redis事务、事务异常、乐观锁、管道
  • 解决odbc 数据源创建之后删除失败问题
  • 抄袭瓜!斯坦福作者已删库跑路!面壁和刘知远老师的最新回应
  • (三)从jvm层面了解线程的启动和停止
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • 【附node操作实例】redis简明入门系列—字符串类型
  • hadoop集群管理系统搭建规划说明
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • Java超时控制的实现
  • Mysql5.6主从复制
  • Netty 4.1 源代码学习:线程模型
  • node和express搭建代理服务器(源码)
  • PAT A1017 优先队列
  • php中curl和soap方式请求服务超时问题
  • React Native移动开发实战-3-实现页面间的数据传递
  • spring security oauth2 password授权模式
  • tensorflow学习笔记3——MNIST应用篇
  • 给github项目添加CI badge
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 老板让我十分钟上手nx-admin
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 容器服务kubernetes弹性伸缩高级用法
  • 一道闭包题引发的思考
  • 用Canvas画一棵二叉树
  • RDS-Mysql 物理备份恢复到本地数据库上
  • ​HTTP与HTTPS:网络通信的安全卫士
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​Python 3 新特性:类型注解
  • (20050108)又读《平凡的世界》
  • (70min)字节暑假实习二面(已挂)
  • (WSI分类)WSI分类文献小综述 2024
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (十五)、把自己的镜像推送到 DockerHub
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • (原創) 未来三学期想要修的课 (日記)
  • (原創) 物件導向與老子思想 (OO)
  • .gitattributes 文件
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .Net Core 笔试1
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题