题目
两个链表的第一个公共节点。
例如:
链表A:1 -> 2 -> 3 -> 6 -> 7
链表B:4 -> 5 -> 6 -> 7
第一个公共节点为6。
解析
方法一,两个栈将链表倒置,从后向前比较
如上面的例子,栈A放置链表A倒置后的结果,依次为7,6,3,2,1。栈B放置链表B倒置后的结果,依次为7,6,5,4。
然后栈A和栈B共同依次出栈,直到最后一个相同的节点为止,此节点就是两个链表的第一个公共节点。
时间复杂度O(m+n),空间复杂度O(m+n)。
方法二,统计链表长度,先走几步,从前向后比较
先遍历两个链表分别得到它们的长度,较长的链表先走几步,当余下节点与短链表长度一致后,再一起出发,找到第一个公共节点。
时间复杂度O(m+n),空间复杂度O(1)。
方法三,两链表的头指针同时出发,当第二次经过第一个公共节点时,会完美相遇
如上面示例,指针A从链表A出发,经过1,2,3,6,7后,走到4,5,6,第二次达到节点6时,走了7步,经过8个节点。指针B从链表B出发,经过4,5,6,7后,走到1,2,3,6,第二次达到节点6时,也走了7步,经过8个节点。两指针正好相遇。
因为两个指针都走过了链表A和链表B分别不同的节点和一次相同的节点路径。路过的节点数相同,所以会在第二次经过第一个公共节点时相遇。如果两链表无公共节点,两指针分别遍历了两个链表的所有节点后,都为null相等,都走过了m+n个节点,遍历结束无公共节点。
时间复杂度O(m+n),空间复杂度O(1)。时间复杂度与方法二一样,但是实际上系数会小一些,方法二两次遍历,系数为2。而方法三不到两次的遍历。
代码
方法三的代码实现
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(null == headA || null == headB){
return null;
}
ListNode node1 = headA;
ListNode node2 = headB;
//两指针第二次走到第一个公共节点,就是两指针的第一次相遇
while(node1 != node2){
//如果两链表有公共节点,指针只有一次指向null
//若两链表无公共节点,指针第二次指向null的时候,while循环结束
node1 = (null == node1) ? headB : node1.next;
node2 = (null == node2) ? headA : node2.next;
}
return node1;
}