论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
ToB企服应用市场:ToB评测及商务社交产业平台
»
论坛
›
软件与程序人生
›
后端开发
›
Java
›
链表是否存在环及其相干题目
链表是否存在环及其相干题目
知者何南
金牌会员
|
2024-12-15 16:11:45
|
显示全部楼层
|
阅读模式
楼主
主题
874
|
帖子
874
|
积分
2622
1.链表中环相干题目
1.1 链表中是否有环
有一个单向链表,链表中有可能出现“环”,就像下图这样。 那么,如何用程序来判断该链表是否为有环链表呢?
思路
创建两个指针p1和p2(在Java里就是两个对象引用),让它们同时指向这个链表的头节点。然后开始一个大循环,在循环体中,让指针p1每次向后移动1个节点,让指针p2每次向后移动2个节点,然后比力两个指针指向的节点是否雷同。假如雷同,则可以判断出链表有环,假如差别,则继承下一次循环。
类似于,小学奥数中的追及题目。此方法就类似于一个追及题目。 在一个环形跑道上,两个活动员从同一所在起跑,一个活动员速度快,另一个活动员速度慢。当两人跑了一段时间后,速度快的活动员必然会再次追上并超过速度慢的活动员,原因很简朴,因为跑道是环形的。 假设链表的节点数量为n,则该算法的时间复杂度为O(n)。除两个指针外,没有利用任何额外的存储空间,所以空间复杂度是O(1)。
1.2 求环长
假如链表有环,如何求出环的长度?
思路
当两个指针首次相遇,证实链表有环的时候,让两个指针从相遇点继承循环前进,并统计前进的循环次数,直到两个指针第2次相遇。此时,统计出来的前进次数就是环长。 因为指针p1每次走1步,指针p2每次走2步,两者的速度差是1步。当两个指针再次相遇时,p2比p1多走了整整1圈。 因此,环长 = 每一次速度差 × 前进次数 = 前进次数。
1.3 求入环节点
思路
上图是对有环链表所做的一个抽象示意图。假设从链表头节点到入环点的距离是D,从入环点到两个指针首次相遇点的距离是S1,从首次相遇点回到入环点的距离 是S2。
那么,当两个指针首次相遇时,各自所走的距离是多少呢?
指针p1一次只走1步,所走的距离是D+S1。 指针p2一次走2步,多走了n(n>=1)整圈,所走的距离是D+S1+n(S1+S2)。 由于p2的速度是p1的2倍,所以所走距离也是p1的2倍,因此: 2(D+S1) = D+S1+n(S1+S2) 等式经过整理得出:D = (n-1)(S1+S2)+S2。
也就是说,从链表头结点到入环点的距离,等于从首次相遇点绕环n-1圈再回到 入环点的距离。
这样一来,只要把其中一个指针放回到头节点位置,另一个指针保持在首次相遇点,两个指针都是每次向前走1步。那么,它们最终相遇的节点,就是入环节点。
1.4 具体代码
/**
* 链表是否存在环问题
*/
public class LinkedListCycle {
/**
* 链表是否有环
* @param head 链表的头节点
*/
public static boolean hasCycle(Node head){
Node p1 = head;
Node p2 = head;
while(p2 != null && p2.getNext().getNext() != null){
p1 = p1.getNext();
p2 = p2.getNext().getNext();
if(p1 == p2)
return true;
}
return false;
}
/**
* 统计链表中环的长度
* @param head 链表的头节点
* @return -1-代表链表中不存在环
*/
public static int countCycleLength(Node head){
if(!hasCycle(head))
return -1;
Node p1 = head;
Node p2 = head;
int count = 0;//记录循环次数
int firstMeet = -1;//记录第一次相遇,循环的次数
int secondMeet = -1;//记录第二次相遇,循环的次数
while(true){
p1 = p1.getNext();
p2 = p2.getNext().getNext();
if(p1 == p2 && firstMeet != -1)//第二次相遇
secondMeet = count;
if(p1 == p2 && firstMeet == -1)//第一次相遇,为firstMeet赋值
firstMeet = count;
if(firstMeet != -1 && secondMeet != -1)//统计出第一次和第二次相遇的循环次数后,可以结束循环了
break;
count++;
}
return secondMeet - firstMeet;
}
/**
* 获取入环节点
* @param head 链表头节点
* @return null-代表链表中不存在环
*/
public static Node getEnterCycleNode(Node head){
if(!hasCycle(head))
return null;
Node p1 = head;
Node p2 = head;
Node firstMeetNode = null;
while(true){
p1 = p1.getNext();
p2 = p2.getNext().getNext();
if(p1 == p2){
firstMeetNode = p1;
break;
}
}
p1 = head;
p2 = firstMeetNode;
Node enterCycleNode = null;
while(true){
p1 = p1.getNext();
p2 = p2.getNext();
if(p1 == p2){
enterCycleNode = p2;
break;
}
}
return enterCycleNode;
}
private static class Node{
int data;
Node next;
Node(int data){
this.data = data;
}
public int getData() {
return data;
}
public Node getNext() {
return next;
}
}
public static void main(String[] args) {
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node2;
System.out.println(hasCycle(node1));//true
System.out.println(countCycleLength(node1));//4
System.out.println(getEnterCycleNode(node1).getData());//2
}
}
复制代码
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
知者何南
金牌会员
这个人很懒什么都没写!
楼主热帖
开源二三事|ShardingSphere 与 Databa ...
SQLServer数据库基础教程
Sqlserver创建用户并授权
「笔记」某移动SRE运维体系交流 ...
这个简单的小功能,半年为我们产研团队 ...
华为再次登上央视!鸿蒙系统3.0今年上 ...
Oracle调度器Scheduler
ESP32-C3 学习测试 蓝牙 篇(六、添加 ...
编程体验1
Kubernetes(K8S) Controller - Statefu ...
标签云
挺好的
服务器
浏览过的版块
网络安全
快速回复
返回顶部
返回列表