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,判断 ...
随机推荐
- Sbulime Text 2 修改选中字符串的颜色
Sublime Text 2 > Preferences > Browse Packages... 假设当前试用的 Color Scheme 是 Monokai,则在 Color Sche ...
- ajax在php中应用实例
1,ajax分为$.ajax(),$.get(),$.post(),$.getJSON() 几种形式,实例如下: <html> <meta http-equiv="Cont ...
- php批量导出pdf文件的脚本(html-PDf)
背景:突然有大量的文件需要导出成PDF文件,写一个批量导出pdf的脚本,同时文件的命名也需要有一定的规则 导出方式:向服务器中上传csv文件,csv文件中包含文件的地址和相对应的文件命名. 如下格式: ...
- 配置阿里云ESC服务器部署项目
第一次SSH登录 ECS 服务器: 打开命令行终端(git),键入: > ssh root@39.108.54.110 输入实例密码,进入服务器环境. 配置 root 及应用账号权限 新增管理员 ...
- Cookie、Session和Cache
一.Cookie Cookie是保存客户端的一组数据,主要用来保存用户的个人信息,主要存放浏览器请求服务器时的请求信息,这些信息是非敏感信息.主要用于当用户访问您的系统时,应用程序可以检索以前存储的信 ...
- pythonweb框架Flask学习笔记03-变量规则
#-*- coding:utf-8 -*- from flask import Flask app=Flask(__name__) @app.route('/post/<int:postid&g ...
- yii2之ActiveForm表单使用
因目前项目并非前后端分离模式,且用到PHP的yii2框架(所有html代码,js较多内嵌在.php文件内多少采用同步提交[喷墨中...]),遂对于前端面上需要用到的yii2小组件一些整理(因是前端若涉 ...
- Java之Spring Boot学习
1.如何配置pdf.xls页面解析器.2.如何整合SpringBoot+JPA+Session+Redis配置.3.SpringBoot整合Mybatis之事务用法.4.JUnit Test单元测试用 ...
- POJ 2377
#include<stdio.h> #define MAXN 1005 #include<iostream> #include<algorithm> #define ...
- (转)rpm2cpio和cpio
原文:https://blog.csdn.net/jubincn/article/details/6687550 rpm2cpio命令:将rpm格式的文件转为cpio格式的文件.rpm是linux中常 ...