尋找兩個鏈表的相交節點

題目:

單鏈表可能有環,也可能無環.給定兩個單鏈表的頭節點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;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章