面試題52:兩個鏈表的第一個公共結點
一、題目描述
輸入兩個鏈表,找出它們的第一個公共結點。
鏈表節點定義如下:
public class ListNode{
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
二、問題分析
最直接的手段是暴力法,遍歷第一個鏈表的結點,每到一個結點,就在第二個鏈表上遍歷每個結點,判斷是否相等。時間複雜度爲O(m*n),效率低,面試中這種解法肯定不會讓面試官滿意。
我們需要點技巧,我們列舉一下吧
方法一:
使用棧:由於公共結點可以從尾部進行判斷,所以用兩個棧分別放入兩個鏈表中的結點,從尾結點開始出棧比較。時間複雜度O(m+n),空間複雜度O(m+n)。
方法二:
之前我們做過劍指Offer對答如流系列 - 鏈表中倒數第k個結點
可以利用長度關係:計算兩個鏈表的長度之差,長鏈表先走相差的步數,之後長短鏈表同時遍歷,找到的第一個相同的結點就是第一個公共結點。
方法三:
之前我們做過劍指Offer對答如流系列 - 鏈表中環的入口節點
利用兩個引用:一個引用順序遍歷list1和list2,另一個引用順序遍歷list2和list1,(這樣兩引用能夠保證最終同時走到尾結點),兩個引用找到的第一個相同結點就是第一個公共結點。
三、問題解答
利用長度關係的解法:
public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int length1 = getLength(pHead1);
int length2 = getLength(pHead2);
int lengthDif = length1-length2;
ListNode longList = pHead1;
ListNode shortList = pHead2;
if(lengthDif<0){
longList = pHead2;
shortList = pHead1;
lengthDif = -lengthDif;
}
for(int i=0;i<lengthDif;i++) {
longList = longList.next;
}
while(longList!=null && longList!=shortList ){
longList=longList.next;
shortList=shortList.next;
}
return longList; //沒有公共結點剛好是null
}
private int getLength(ListNode head){
int len=0;
while(head!=null){
len++;
head=head.next;
}
return len;
}
利用兩個引用的解法
public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p1=pHead1;
ListNode p2=pHead2;
while(p1!=p2){
p1= (p1==null ? pHead2 : p1.next);
p2= (p2==null ? pHead1 : p2.next);
}
return p1;
}