給定兩個可能有環也可能無環的單鏈表,頭結點head1和head2.請實現一個函數,如果兩個鏈表相交,請返回相交的第一個節點,如果不相交,返回null
要求:
如果兩個鏈表長度之和爲N,時間複雜度請達到O(N),額外空間複雜度請達到O(1)
先解決這樣一個問題:
給定一個存在環的單鏈表,請找出環的入口結點,如果一個單鏈表的首尾結點是同一個結點,則默認首結點爲環的入口結點。
package com.inspire.chapter6;
public class Code05_FindFirstIntersectNode1 {
public static class Node {
public int value;
public Node next;
public Node(int v) {
value = v;
}
}
//判斷單鏈表是否存在環,有環返回環的入口結點,無環返回null
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node slow = head.next;
Node fast = head.next.next;
while (slow != fast) {
if (fast.next == null || fast.next.next == null) {
return null;
}
slow = slow.next;
fast = fast.next.next;
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
public static void main(String[] args) {
Node head = new Node(1);
head.next = new Node(2);
head.next.next = new Node(3);
head.next.next.next = new Node(4);
head.next.next.next.next = new Node(5);
head.next.next.next.next.next = new Node(6);
head.next.next.next.next.next.next = new Node(7);
head.next.next.next.next.next.next.next = head.next.next.next;
System.out.println(getLoopNode(head).value);
}
}
接下來解決這道題
假設鏈表head1和鏈表head2各自的入環結點分別爲loop1和loop2
1.loop1=null,loop2=null;
首先判斷這兩個鏈表是否存在環,當兩個鏈表都不存在環時
情況1:兩個鏈表的不相交,返回null,判斷方法:兩個鏈表的尾結點不相等;
情況2:兩個鏈表相交,返回相交結點,判斷方法,分別存在兩個結點相等。
2.loop1=null,loop2!=null;loop1!=null,loop2=null;這種兩種情況下兩個鏈表是不會相交的
3.loop1!=null,loop2!=null;
情況一:兩個鏈表沒有共同結點(不相交)
情況二:兩個鏈表的相交結點不在環上(也即入環結點相等)
情況三:兩個鏈表的相交結點在環上(也即入環結點不相等)
package com.inspire.chapter6;
import com.inspire.chapter6.Test2.Node;
public class Code05_FindFirstIntersectNode {
public static class Node {
public int value;
public Node next;
public Node(int v) {
value = v;
}
}
// 判斷單鏈表是否存在環,有環返回環的入口結點,無環返回null
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node slow = head.next;
Node fast = head.next.next;
while (slow != fast) {
if (fast.next == null || fast.next.next == null) {
return null;
}
slow = slow.next;
fast = fast.next.next;
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
// 根據兩個無環鏈表查找相交結點,有則返回相交結點,沒有則返回null
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
// 判斷兩個單鏈表的尾結點是否相等,不相等則返回null,相等則繼續
Node cur1 = head1;
Node cur2 = head2;
int n = 0;// 保存兩個單鏈表長度的差值
while (cur1 != null) {
n++;
cur1 = cur1.next;
}
while (cur2 != null) {
n--;
cur2 = cur2.next;
}
if (cur1 != cur2) {// 說明不相交
return null;
}
cur1 = n > 0 ? head1 : head2;// cur1指向較長的單鏈表
cur2 = cur1 == head1 ? head2 : head1;// cur2指向較短的單鏈表
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
} // 退出循環後,較長的單鏈表中cur1指向結點開始的單鏈表已經和較短的單鏈表長度相等了
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
// 兩個有環鏈表,返回第一個相交節點,如果不想交返回null
/*
* loop1:鏈表head1的入環結點 loop2:鏈表head2的入環結點
*/
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
if (loop1 == loop2) {// 這是情況二
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop1) {
n--;
cur2 = cur2.next;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
} else {// 討論情況一和情況三
Node cur1 = loop1.next;
while (cur1 != loop1) {
if (cur1 == loop2) {
return loop1;
}
cur1 = cur1.next;
}
return null;
}
}
public static Node getIntersectNode(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node loop1 = getLoopNode(head1);
Node loop2 = getLoopNode(head2);
if (loop1 == null && loop2 == null) {
return noLoop(head1, head2);
} else if (loop1 != null && loop2 != null) {
return bothLoop(head1, loop1, head2, loop2);
}
return null;
}
public static void main(String[] args) {
// 1->2->3->4->5->6->7->null
Node head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
// 0->9->8->6->7->null
Node head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
// 1->2->3->4->5->6->7->4...
head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
head1.next.next.next.next.next.next = head1.next.next.next; // 7->4
// 0->9->8->2...
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next; // 8->2
System.out.println(getIntersectNode(head1, head2).value);
// 0->9->8->6->4->5->6..
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);
}
}