給一個單鏈表,判斷其中是否有環的存在 兩個思路: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