面试题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;
}