1:三個(gè)基本的問題點(diǎn)
1.單鏈表是否有環(huán)视哑?
2.有則輸出環(huán)的長度葬项?
3.找到環(huán)的入口節(jié)點(diǎn)?
分析:
定義兩個(gè)指針fast 和slow梧却,fast每次向后移動(dòng)兩個(gè)節(jié)點(diǎn)奇颠,slow每次想后移動(dòng)一個(gè)節(jié)點(diǎn)。
1.如果沒有環(huán)放航,則fast首先到達(dá)鏈表結(jié)尾烈拒;
2.鏈表有環(huán)的情況下:fast與slow兩次相遇,slow中間走過的節(jié)點(diǎn)處即為環(huán)的長度广鳍;
3.找環(huán)的入口節(jié)點(diǎn)稍微復(fù)雜點(diǎn)荆几,有如下的推導(dǎo)過程:
相遇的時(shí)候,slow共移動(dòng)了s步赊时,fast共移動(dòng)了2s步吨铸。
定義a如下: 鏈表頭移動(dòng)a步到達(dá)入口點(diǎn)。
定義x如下: 入口點(diǎn)移動(dòng)x步到達(dá)相遇點(diǎn)祖秒。
定義r如下: 環(huán)的長度诞吱。
定義L如下: 鏈表總長度為L。
其中L”蜂獭= a + r
那么slow和fast相遇了狐胎,fast必然比slow多走了n個(gè)圈,也就是 nr 步歌馍,那么
s = a + x
2s = s + nr 握巢, 可得 s = nr
將s=a+x,帶入s =nr松却,可得 a+x = nr, 也就是 a+x = (n-1)r + r
從表頭移動(dòng)到入口點(diǎn)暴浦,再從入口點(diǎn)移動(dòng)到相遇點(diǎn),也就是移動(dòng)了整個(gè)鏈表的距離晓锻,即是 L = a + r , 所以r = L - a
所以 a+x = (n-1)r + L - a , 于是 a = (n-1)r + L - a - x
得到:從表頭到入口點(diǎn)的距離歌焦,等于從相遇點(diǎn)到入口點(diǎn)的距離。
所以砚哆,從表頭設(shè)立一個(gè)指針独撇,從相遇點(diǎn)設(shè)立一個(gè)指針,兩個(gè)同時(shí)移動(dòng)躁锁,必然能夠在入口點(diǎn)相遇纷铣,這樣,就求出了相遇點(diǎn)战转。
2:實(shí)現(xiàn)方式
2.1:判斷是否存在環(huán)
private static boolean hasCircleNode(Node head) {
if (head == null) {
return false;
}
Node fast = head;
Node slow = head;
while (fast != null && fast.getNext() != null) {
fast = fast.next.next;
slow = slow.next;
if (slow.value == fast.value) {
return true;
}
}
return false;
}
2.2:環(huán)的長度
public static void circleLength(Node head) {
if (head == null) {
return ;
}
Node slow = head;
Node fast = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
int len = 1;
fast = fast.next.next;
slow = slow.next;
while (fast != slow) {
len++;
fast = fast.next.next;
slow = slow.next;
}
System.out.println("circle length==" + len);
}
}
}
2.3:環(huán)的入口
public static void circleLength(Node head) {
if (head == null) {
return ;
}
Node slow = head;
Node fast = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
int len = 1;
fast = fast.next.next;
slow = slow.next;
while (fast != slow) {
len++;
fast = fast.next.next;
slow = slow.next;
}
System.out.println("circle length==" + len);
fast = head;------------>輸出環(huán)入口節(jié)點(diǎn)
while (fast != slow) {
fast= fast.next;
slow = slow.next;
}
System.out.println("circle point==" + slow.value);
}
}
}