1. 程式人生 > >leetcode-160- 相交連結串列(intersection of two linked list)-java

leetcode-160- 相交連結串列(intersection of two linked list)-java

題目及測試

package pid160;
/*   相交連結串列

編寫一個程式,找到兩個單鏈表相交的起始節點。

 

例如,下面的兩個連結串列:

A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3

在節點 c1 開始相交。

 

注意:

    如果兩個連結串列沒有交點,返回 null.
    在返回結果後,兩個連結串列仍須保持原有的結構。
    可假定整個連結串列結構中沒有迴圈。
    程式儘量滿足 O(n) 時間複雜度,且僅用 O(1) 記憶體。

 

致謝:
特別感謝 @stellari 新增此問題並建立所有測試用例。



*/
public class main {
	
public static void main(String[] args) {
		ListNode c=new ListNode(0);
		c.next=new ListNode(-1);
		
		LinkList a=new LinkList(1);
		a.addLast(2);
		a.addLast(3);
		a.first.next.next.next=c;
		a.printList();
		//test(a.first);
		
		LinkList b=new LinkList(5);
		b.addLast(6);
		b.addLast(4);
		b.addLast(2);
		b.first.next.next.next.next=c;
		b.printList();
		test(a.first,b.first);		
		/*
		LinkList c=new LinkList(1);
		c.addLast(2);
		c.addLast(2);
		c.addLast(1);
		c.printList();
		//test(c.first);
		
		
		LinkList d=new LinkList(1);
		d.addLast(2);
		d.addLast(3);
		
		c.printList();		
		d.printList();
		test(c.first,d.first);*/
	}
		 
	private static void test(ListNode ito,ListNode ito2) {
		Solution solution = new Solution();
		ListNode rtn;
		long begin = System.currentTimeMillis();
		System.out.println();
		//開始時列印陣列
		
		rtn=solution.getIntersectionNode(ito,ito2);//執行程式
		long end = System.currentTimeMillis();	
		System.out.println("rtn=");
		rtn.printNodeToEnd();
		
		//System.out.println(":rtn" );
		//System.out.print(rtn);
		System.out.println();
		System.out.println("耗時:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,2ms,超快)

首先有一點非常重要,相交節點後的所有節點 (包括相交節點) 都是兩個連結串列共享的。

我們將兩個連結串列的右端對齊,長度較大的連結串列 的左端的 多出來的節點 肯定不是相交節點,所以我們不考慮左端的這一部分的節點

使用雙指標演算法,先遍歷一遍兩個連結串列的長度,再將兩個指標指向兩個連結串列頭部,移動長的連結串列的指標,指向相同距離的位置,再兩個指標一起走,如果指標相遇,則得到相同節點

package pid160;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    if(headA==null||headB==null){
    	return null;
    }
    int lengthA=0;
    int lengthB=0;
    ListNode now=headA;
    while(now!=null){
    	lengthA++;
    	now=now.next;
    }
    now=headB;
    while(now!=null){
    	lengthB++;
    	now=now.next;
    }
    ListNode nowA=headA;
    ListNode nowB=headB;
    if(lengthA>lengthB){
    	for(int i=0;i<lengthA-lengthB;i++){
    		nowA=nowA.next;
    	}
    }
    if(lengthA<lengthB){
    	for(int i=0;i<lengthB-lengthA;i++){
    		nowB=nowB.next;
    	}
    }
    ListNode result=null;
    while(true){
    	if(nowA==nowB){
    		result=nowA;
    		break;
    	}
    	if(nowA==null||nowB==null){
    		break;
    	}
    	nowA=nowA.next;
    	nowB=nowB.next;    	
    }   	
	return result;
    }
}

網上還有兩種解法,都不太好

有以下幾種思路:
(1)暴力破解,遍歷連結串列A的所有節點,並且對於每個節點,都與連結串列B中的所有節點比較,退出條件是在B中找到第一個相等的節點。時間複雜度O(lengthA*lengthB),空間複雜度O(1)。

(2)雜湊表。遍歷連結串列A,並且將節點儲存到雜湊表中。接著遍歷連結串列B,對於B中的每個節點,查詢雜湊表,如果在雜湊表中找到了,說明是交集開始的那個節點。時間複雜度O(lengthA+lengthB),空間複雜度O(lengthA)或O(lengthB)。