Q:判断链表中是否存在环的相关问题
问题:如何判断一个单向链表中是否存在环?
例如:
链表中存在环(B-->D):
<-- <--^
| |
v |
A-->B-->C-->D
链表中不存在环:
A-->B-->C-->D-->E-->F
解题思路:
从一个实际的生活场景出发,两个人,在一个环形的操场上跑步的时候,如果有一个人跑得比另一个人还要快,那么,在n圈之后,这两个人总会在操场上的某个点相遇。将操场类比于链表中存在的环路径,将两个人看成两个指针,那么这道题的解题思路就自然而然的出来了。
具体步骤如下:
- 初始化两个指针a,b,同时指向链表的开头
- a指针走一步,b指针走两步(我们姑且将a指针称为慢指针,将b指针称为快指针)
- 重复步骤2,直到b指针无法继续往下走两步或者a,b指针相遇
- 当b指针无法继续往下走两步的时候,说明链表中不存在环,b指针即将走到链表的末尾端。
- 当a,b指针相遇,说明链表中存在环,因为只有存在环的情况,a,b指针才有可能会在环中的某个点相遇
具体代码如下:
/**
* @author 学徒
*
* 用于判断链表中是否存在环
*
*/
public class CycleLinkedList {
/**
* 循环链表中的节点类
*/
static class Node<T>{
//节点值
T value;
//节点的下一个节点的指针
Node<T> next;
public Node(T value){
this(value,null);
}
public Node(T value,Node next){
this.next=next;
this.value=value;
}
}
/**
* 用于判断该链表中是否存在着环
* @param head 链表的头节点
* 当存在环时,返回true,否则返回false
*/
public boolean judge(Node head) {
if(head==null){
return false;
}
//两个指向头结点的指针
Node a=head,b=head;
while(true){
if(b.next==null||b.next.next==null){
return false;
}
a=a.next;
b=b.next.next;
if(a==b){
return true;
}
}
}
public static void main(String[] args){
Node<String> a=new Node<String>("A");
Node<String> b=new Node<String>("B");
Node<String> c=new Node<String>("C");
Node<String> d=new Node<String>("D");
a.next=b;
b.next=c;
c.next=d;
d.next=b;
CycleLinkedList list=new CycleLinkedList();
boolean result=list.judge(a);
System.out.println("链表中环的结果:"+result);
}
}
从上面的链表中是否存在环的问题,可以延伸出与链表中是否存在环相关的另一个问题
问题: 链表中构成环的元素的个数应该如何计算?
对于这个问题,我们稍微沿着解决上面的链表存在环的问题的思路继续往下想,当链表中存在环的时候,快慢指针相遇,那么这个时候,我们只需要让快指针停留在相遇的位置,让慢指针再次走一遍,边走边记录步数,当快慢指针再次相遇的时候,慢指针所走的步数,便是构成环的链表的环中元素个数。
我们只需要稍微修改下上面的代码即可,具体代码如下:
/**
* @author 学徒
*
* 用于判断链表中是否存在环
*
*/
public class CycleLinkedList {
/**
* 循环链表中的节点类
*/
static class Node<T>{
//节点值
T value;
//节点的下一个节点的指针
Node<T> next;
public Node(T value){
this(value,null);
}
public Node(T value,Node next){
this.next=next;
this.value=value;
}
}
/**
* 用于判断该链表中是否存在着环
* @param head 链表的头节点
* 当存在环时,返回环中元素个数,否则返回0
*/
public int judge(Node head) {
if(head==null) {
return 0;
}
//两个指向头结点的指针
Node a=head,b=head;
while(true){
//当出现该情况的时候,说明无环
if(b.next==null||b.next.next==null){
return 0;
}
a=a.next;
b=b.next.next;
//当其存在环
if(a==b){
int number=1;
a=a.next;
while(a!=b){
a=a.next;
number++;
}
return number;
}
}
}
public static void main(String[] args){
Node<String> a=new Node<String>("A");
Node<String> b=new Node<String>("B");
Node<String> c=new Node<String>("C");
Node<String> d=new Node<String>("D");
a.next=b;
b.next=c;
c.next=d;
d.next=b;
CycleLinkedList list=new CycleLinkedList();
int result=list.judge(a);
System.out.println(result);
}
}
顺着上面的问题继续的往下想,我们可以延伸出另一个问题
问题:我们是否可以得到第一个进入该链表的环的节点的元素?
对于该问题,我们可以通过以下的方式得到该节点。
- 将快指针重新指向链表的头节点
- 快指针和慢指针同时走,当快指针和慢指针相遇时,该节点便是链表中第一个进入环的节点
ps:以上只是一个结论的步骤总结。实际上,可以通过分析得到,在环中,快慢指针第一次相遇时的节点位置与进入环的第一个节点的顺时针方向的距离同链表头节点到进入环中第一个节点的位置的距离相等。
具体代码如下:
/**
* @author 学徒
*
* 用于判断链表中是否存在环
*
*/
public class CycleLinkedList {
/**
* 循环链表中的节点类
*/
static class Node<T>{
//节点值
T value;
//节点的下一个节点的指针
Node<T> next;
public Node(T value){
this(value,null);
}
public Node(T value,Node next){
this.next=next;
this.value=value;
}
}
/**
* 用于判断该链表中是否存在着环
* @param head 链表的头节点
* 当存在环时,返回环中元素个数,否则返回0
*/
public Node judge(Node head) {
if(head==null) {
return null;
}
//两个指向头结点的指针
Node a=head,b=head;
while(true){
//当出现该情况的时候,说明无环
if(b.next==null||b.next.next==null){
return null;
}
a=a.next;
b=b.next.next;
//当其存在环
if(a==b){
b=head;
while(a!=b){
a=a.next;
b=b.next;
}
return b;
}
}
}
public static void main(String[] args){
Node<String> a=new Node<String>("A");
Node<String> b=new Node<String>("B");
Node<String> c=new Node<String>("C");
Node<String> d=new Node<String>("D");
a.next=b;
b.next=c;
c.next=d;
d.next=b;
CycleLinkedList list=new CycleLinkedList();
Node result=list.judge(a);
System.out.println(result.value);
}
}
主目录:
Q:判断链表中是否存在环的相关问题的更多相关文章
- <数据结构>XDOJ323.判断有向图中是否有环
问题与解答 问题描述 判断有向图中是否有环. 输入格式 输入数据第一行是一个正整数,表示n个有向图,其余数据分成n组,每组第一个为一个整数,表示图中的顶点个数n,顶点数不超过100,之后为有向图的邻接 ...
- LeetCode -- 推断链表中是否有环
思路: 使用两个节点.slow和fast,分别行进1步和2步.假设有相交的情况,slow和fast必定相遇:假设没有相交的情况,那么slow或fast必定有一个为null 相遇时有两种可能:1. 仅仅 ...
- 查找链表中是否有环linked-list-cycle
Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...
- [Leetcode] Linked list cycle 判断链表是否有环
Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...
- leetcode - 链表两两元素交换 + 判断链表有无环
链表两两元素交换 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表. 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换. 示例: 给定 1->2->3->4, 你 ...
- [LeetCode] Linked List Cycle II 单链表中的环之二
Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Foll ...
- POJ 1860 Currency Exchange(如何Bellman-Ford算法判断图中是否存在正环)
题目链接: https://cn.vjudge.net/problem/POJ-1860 Several currency exchange points are working in our cit ...
- [LeetCode] 142. Linked List Cycle II 单链表中的环之二
Given a linked list, return the node where the cycle begins. If there is no cycle, return null. To r ...
- 判断链表是否有环(Java实现)
判断给定的链表中是否有环.如果有环则返回true,否则返回false. 解题思路:设置两个指针,slow和fast,fast每次走两步,slow每次走一步,如果有环的话fast一定会追上slow,判断 ...
随机推荐
- C++ STL的容器类型
1.顺序容器 2.关联容器 3.vector的使用 vector<数据类型> a; a.push_back(10) -------->把数据从末末尾段插入vector里面 a.po ...
- Exp3 免杀原理与实践 20164321 王君陶
Exp3 免杀原理与实践 20164321 王君陶 1实验要求 1.1 正确使用msf编码器(0.5分),msfvenom生成如jar之类的其他文件(0.5分),veil-evasion(0.5分), ...
- umeng推送, 生产环境deviceToken失效可能原因
1 在系统升级之后会造成app的deviceToken重置(一定). 2 在app卸载之后可能会造成app的deviceToken重置. 3 deviceToken重置使用umeng推送时会因为dev ...
- 2018年Android面试题含答案--适合中高级(下)
这里是我整理出来的面试题,答案我花了很久的时间.加上我自己的理解整理出来的,作者不易,请谅解.有答案的的:https://xiaozhuanlan.com/topic/6132940875 1.A ...
- Apache TraceEnable关闭与测试方法
系统环境:OS: RHEL5.6_x64Apache: httpd-2.2.11 关闭方法:在主配置文件httpd.conf中添加配置:TraceEnable off可以直接配置在ServerRoot ...
- centos 6 下,zephir的安装和使用
centos 6 下,zephir的安装和使用 zephir或许会开启一个新的PHP编写方式. 在这之前,如果我们要编写php的扩展,一般都是c++/clang/vc等等. 但是现在,我们有了新的选择 ...
- 【wireshark】Wireshark原理分析与二次开发系列
1.版权声明 本系列文章是本人花了很多心血写成,wireshark本是开源软件,本人也乐于技术知识和经验的分享,更是欣赏和推崇开源精神,因此任何看到本文的人都可以随意转载,但只有一个要求: 在大段甚至 ...
- centos6下无法使用lsof命令"-bash: lsof: command not found"
1. 问题描述在centos下, 无法使用命令lsof, 出现以下信息:# lsof -i:3690-bash: lsof: command not found2. 解决方法我们可以通过yum来安装: ...
- Optimizing Your App for Today’s Internet
这个 session 的主讲人感觉是一个很典型的美国人,年纪也不小. 网络现状 四十亿人在使用因特网,大概占有世界人口的一半.上网人数的增长在减缓. 但是网络仍然在增长.增长点主要在物联网.第三世界国 ...
- Web应用配置虚拟主机(www.baidu.com)
最终效果:浏览器地址栏输入www.baidu.com访问时,会显示自己的网页 1.创建文件 任意盘新建一个www.baidu.com文件,在该文件夹下新建WEB-INF文件.自己写的一个html文件, ...