題目:輸入兩個鏈表,找出它們的第一個公共結點。面試
面試的時候碰到這道題,不少應聘者的第一反應就是蠻力法:在第一鏈表 上順序遍歷每一個結點,沒遍歷到一個結點的時候,在第二個鏈表上順序遍歷每一個結點。若是在第二個鏈表上有一個結點和第一個鏈表上的結點同樣,說明兩個鏈表在 這個結點上重合,因而就找到了他們的公共結點。若是第一個鏈表的長度爲m,第二個鏈表的長度爲n,顯然該方法的時間複雜度爲O(mn).get
一般蠻力法不會是最好的辦法,咱們接下來試着分析有公共結點的兩個鏈 表有哪些特色。從鏈表結點的定義能夠看出,這兩個鏈表是單鏈表。若是兩個單向鏈表有公共的結點,那麼這兩個鏈表從某一結點開始,它們的m_pNext都指 向同一個結點,但因爲是單向鏈表的結點,以後他們全部結點都是重合的,不可能再出現分叉。因此兩個有公共結點而部分重合的鏈表,拓撲形狀開起來像一個Y, 而不可能項X。class
通過分析咱們發現,若是兩個鏈表有公共結點,那麼公共結點出如今兩個 鏈表的尾部。若是咱們從兩個鏈表的尾部開始往前比較,最後一個相同的結點就是咱們要找的結點。可問題是在單向鏈表中,咱們只能從頭結點開始按順序遍歷,最 後才能到達尾節點。最後到達的尾節點卻要最早被比較,這聽起來是否是像後進先出,也是咱們就能想到用棧的特色來解決這個問題:分別把兩個鏈表的結點放入兩 個棧裏,這樣兩個鏈表的尾節點就位於兩個棧的棧頂,接下來比較兩個棧頂的結點是否相同。若是相同,則把棧頂彈出接着比較下一個棧頂,直到找到最後一個相同 的結點。test
在上述思路中,咱們須要用兩個輔助棧。若是鏈表的長度分別爲m和n,那麼空間複雜度是O(m+n)。這種思路的時間複雜度也是O(m+n).和最開始的蠻力法相比,時間效率獲得了提升,至關因而用空間消耗換取了時間效率。效率
之因此須要用到棧,是由於咱們想同時遍歷到達兩個棧的尾節點。當兩個 鏈表的長度不相同時,若是咱們從頭開始遍歷到達兩個棧的尾節點的時間就不一致。其實解決這個問題還有一個更簡單的辦法:首先遍歷兩個鏈表獲得他們的長度, 就能知道哪一個鏈表比較長,以及長的鏈表比短的鏈表多幾個結點。在第二次遍歷的時候,在較長的鏈表上先走若干步,接着再同時在兩個鏈表上遍歷,找到第一個相 同的結點就是他們的第一個公共結點。List
第三種思路比第二種思路相比,時間複雜度爲O(m+n),但咱們不在須要輔助棧,所以提升了空間效率。當面試官確定了咱們的最後一個思路的時候,能夠動手寫代碼了。遍歷
Java代碼實現:方法
package cglib;im
class ListNode{
int data;
ListNode nextNode;
}鏈表
public class jiekou {
public static void main(String[] args) {
ListNode head1=new ListNode();
ListNode second1=new ListNode();
ListNode third1=new ListNode();
ListNode forth1=new ListNode();
ListNode fifth1=new ListNode();
ListNode head2=new ListNode();
ListNode second2=new ListNode();
ListNode third2=new ListNode();
ListNode forth2=new ListNode();
head1.nextNode=second1;
second1.nextNode=third1;
third1.nextNode=forth1;
forth1.nextNode=fifth1;
head2.nextNode=second2;
second2.nextNode=forth1;
third2.nextNode=fifth1;
head1.data=1;
second1.data=2;
third1.data=3;
forth1.data=6;
fifth1.data=7;
head2.data=4;
second2.data=5;
third2.data=6;
forth2.data=7;
jiekou test=new jiekou();
System.out.println(test.findFirstCommonNode(head1, head2).data);
}
public ListNode findFirstCommonNode(ListNode head1,ListNode head2){
int len1=getListLength(head1);
int len2=getListLength(head2);
ListNode longListNode=null;
ListNode shortListNode=null;
int dif=0;
if(len1>len2){
longListNode=head1;
shortListNode=head2;
dif=len1-len2;
}else{
longListNode=head2;
shortListNode=head1;
dif=len2-len1;
}
for(int i=0;i<dif;i++){ longListNode=longListNode.nextNode;
}
while(longListNode!=null&&shortListNode!=null
&&longListNode!=shortListNode){ longListNode=longListNode.nextNode; shortListNode=shortListNode.nextNode;
}
return longListNode;
}
private int getListLength(ListNode head1) {
int result=0;
if(head1==null)
return result;
ListNode point=head1;
while(point!=null){
point=point.nextNode;
result++;
}
return result;
}
}
輸出:6