给一个单链表,判断其中是否有环的存在 两个思路:1、如果链表元素没有重复的,则可以用一个set集合存放链表的value,查看是否有重复的 2、如果有重复的,可以设置两个快慢指针fast、slow,若是fast能够追上slow则有环
public class LinkedList {
public void print(LinkedNode<Integer> root){
LinkedNode<Integer> tmp = root;
while (tmp!=null){
System.out.print(tmp.value+" ");
tmp = tmp.next;
}
System.out.println();
}
//创建链表
public LinkedNode<Integer> constructLinkedList(LinkedNode<Integer>... nodes){
LinkedNode<Integer> root = new LinkedNode<>(0);
LinkedNode<Integer> tmp = root;
for(LinkedNode<Integer> node:nodes){
tmp.next = node;
tmp = tmp.next;
}
return root.next;
}
/**
* 2、给一个单链表,判断其中是否有环的存在
* 思路:1、如果链表元素没有重复的,则可以用一个set集合存放链表的value,查看是否有重复的
* 2、如果有重复的,可以设置两个快慢指针fast、slow,若是fast能够追上slow则有环
*/
@Test
public void test2(){
LinkedNode<Integer> node11 = new LinkedNode<>(1);
LinkedNode<Integer> node12 = new LinkedNode<>(3);
LinkedNode<Integer> node13 = new LinkedNode<>(5);
LinkedNode<Integer> node14 = new LinkedNode<>(8);
LinkedNode<Integer> node15 = new LinkedNode<>(9);
LinkedNode<Integer> node16 = new LinkedNode<>(10);
LinkedNode<Integer> node17 = new LinkedNode<>(12);
LinkedNode<Integer> node18 = new LinkedNode<>(11);
LinkedNode<Integer> node19 = new LinkedNode<>(17);
LinkedNode<Integer> root = constructLinkedList(node11,node12,node13,node14,node15,node16,node17,node18,node19);
node19.next = node15;
//方法1 set法
LinkedNode<Integer> tmp = root;
Set<Integer> set = new HashSet<>();
while (tmp!=null){
if(set.contains(tmp.value)){
System.out.println("this linked list has circle and it's start node is "+tmp.value);
break;
}
set.add(tmp.value);
tmp = tmp.next;
}
//方法2:快慢法
/**
* 快慢法原理
* a、第一步,找环中相汇点。分别用fast,slow指向链表头部,slow每次走一步,fast每次走二步,直到fast==slow找到在环中的相汇点。
*
* b、第二步,找环的入口。接上步,当fast==slow时,fast所经过节点数为2x,slow所经过节点数为x,
* 设环中有n个节点,fast比slow多走一圈有2x=n+x; n=x;
*
* 可以看出slow实际走了一个环的步数,再让fast指向链表头部,slow位置不变。
*
* 假设链表开头到环接口的距离是y,如下图所示,那么x-y表示slow指针走过的除链表开头y在环中走过的距离,那么slow再走y步,
* 此时fast结点与slow结点相遇,fast == slow ,x-y+y=x = n,即此时slow指向环的入口。
*/
LinkedNode<Integer> fast = root;
LinkedNode<Integer> slow = root;
int x = 0;
int circleLen = 0; //链表环的长度
while (fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
circleLen ++;
x ++;
if(fast.value == slow.value){
System.out.println("x = "+x);
break;
}
}
fast = root;
int startToCircleHeadLen = 0; // 链表头结点到环接口距离
while (fast!=null && slow!=null){
fast = fast.next;
slow = slow.next;
startToCircleHeadLen ++;
if(fast.value == slow.value){
System.out.println("circle start value : "+fast.value);
break;
}
}
System.out.println("circle len = "+circleLen);
System.out.println("startToCircleHead len = "+startToCircleHeadLen);
//此时 slow节点在环的接口处
//寻找距离接口节点最远的节点
LinkedNode<Integer> circleStartNode = slow;
while (slow!=null && fast !=null){
slow = slow.next;
fast = fast.next.next;
if(circleStartNode == fast || circleStartNode.next == fast){
System.out.println("circle start node = "+circleStartNode.value+",max len node = "+slow.value);
break;
}
}
}
}
输出:
this linked list has circle and it's start node is 9
this linked list has circle
circle start value : 9
circle len = 5
startToCircleHead len = 4
circle start node = 9,max len node = 11