題目:
單鏈表可能有環,也可能無環.給定兩個單鏈表的頭節點head1和head2,這兩個鏈表可能相交,也可能不相交.請實現一個函數,如果兩個鏈表相交,請返回相交的第一個節點;如果不相交,返回null即可.
要求 : 如果鏈表1的長度爲N,鏈表2的長度爲M,時間複雜度請達到 O(N+M),額外空間複雜度請達到O(1).
解題思路:
這個題可以分爲三個題來做.求解此題也是三個步驟.
1-判斷是否有環.
可能兩個都無環,也可能兩個都有環或者一個有環一個無環.
2-全部無環找到第一個交點.
兩個無環單鏈表,如果最後一個節點不是同一個節點,則兩個鏈表一定不相交.
3-全部有環分兩種情況找到第一個交點.
全部有環相交分爲兩種情況:
a-相交之後入環
如果兩條鏈表的入環點相同則爲相交後入環,求交點的步驟同判斷無環鏈表交點相同.
b-入環之後相交
若鏈表A入環之後的某一個點同鏈表B的入環點相同,則兩個鏈表爲入環後相交,也就是兩個鏈表擁有同一個環但入環點不同.
此種情況返回兩個入環點任意一個即可.
說明:兩鏈表一個有環一個無環不可能相交
代碼如下:
package com.lwx.sort;
public class FindFirstIntersectionNode {
public static void main(String[] args) {
}
public static Node getIntersectionNode(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);
}
if(loop1 != null && loop2 != null){
return bothLoop(head1,head2,loop1,loop2);
}
return null;
}
/**
* 兩個有環鏈表求交點
a-相交之後入環
如果兩條鏈表的入環點相同則爲相交後入環,求交點的步驟同判斷無環鏈表交點相同.
b-入環之後相交
若鏈表A入環之後的某一個點同鏈表B的入環點相同,則兩個鏈表爲入環後相交,也就是兩個鏈表擁有同一個環但入環點不同.
此種情況返回兩個入環點任意一個即可.
* @param head1
* @param head2
* @param loop1
* @param loop2
* @return
*/
public static Node bothLoop(Node head1, Node head2,Node loop1, Node loop2){
Node cur1 = null;
Node cur2 = null;
if(loop1 == loop2){
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1){
cur1 = cur1.next;
n++;
}
while(cur2 != loop2){
cur2 = cur2.next;
n--;
}
cur1 = n > 0 ? head1 : head2;
cur2 = head1 == cur1 ? head2 : head1;
n = Math.abs(n);
while(n != 0){
cur1 = cur1.next;
n--;
}
return cur1;
}else{
cur1 = loop1.next;
while(cur1 != loop1){
if(cur1 == loop2){
return loop1;
}
cur1 = cur1.next;
}
}
return null;
}
/**
* 兩個無環鏈表求交點.
* 若最後一個節點相同則擁有交點.
* 兩個鏈表比較一下長度差,長的先走完差值然後兩個鏈表一同next.第一個相同的點爲交點.
* @param head1
* @param head2
* @return
*/
@SuppressWarnings("unused")
public static Node noLoop(Node head1, Node head2){
int n = 0;
Node temp1 = head1;
while(temp1 != null){
temp1 = temp1.next;
n++;
}
Node temp2 = head2;
while(temp2 != null){
temp2 = temp2.next;
n--;
}
if(temp1 != temp2){
return null;
}
temp1 = n > 0? head1 : head2;
temp2 = temp1 == head1 ? head2 : head1;
n = Math.abs(n);
while(n != 0){
temp1 = temp1.next;
n--;
}
while(temp1 != null){
temp1 = temp1.next;
temp2 = temp2.next;
}
return temp1;
}
/**
* 獲得鏈表的入環點,無環則返回null
* 兩個指針一快一慢一同遍歷鏈表.當快指針等於滿指針時,快指針回到開頭開始一步一步走.此時快慢指針再相遇的點就是交點.
* @param head
* @return
*/
@SuppressWarnings("null")
public static Node getLoopNode(Node head){
if(head==null && head.next == null && head.next.next == null){
return null;
}
Node n1 = head.next;
Node n2 = head.next.next;
while(n1 != n2){
if(n2.next == null && n2.next.next == null){
return null;
}
n1 = n1.next;
n2 = n2.next.next;
}
n2 = head;
while(n1 != n2){
n1 = n1.next;
n2 = n2.next;
}
return n1;
}
}
class Node{
int value;
Node next;
Node(int value){
this.value = value;
}
public Node append(Node next){
if(this.next == null){
this.next = next;
}else{
this.next.append(next);
}
return this;
}
}