题目:输入两个链表,找出它们的第一个公共结点。面试
面试的时候碰到这道题,不少应聘者的第一反应就是蛮力法:在第一链表 上顺序遍历每一个结点,没遍历到一个结点的时候,在第二个链表上顺序遍历每一个结点。若是在第二个链表上有一个结点和第一个链表上的结点同样,说明两个链表在 这个结点上重合,因而就找到了他们的公共结点。若是第一个链表的长度为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