题目描述
输入两个链表,找出它们的第一个公共结点。
解法一:
借助辅助空间,可以记录下链表一中的所有节点,再遍历链表二,每遍历到一个节点都判断该节点是否在链表一中存在,第一个存在的节点便是要求节点。
这种解法在链表较短时可以接受,但是数据量增加后产生的空间代价便让人无法接受。
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
Set<ListNode> set = new HashSet<ListNode>();
while(pHead1 != null) {
set.add(pHead1);
pHead1 = pHead1.next;
}
while(pHead2 != null) {
if(set.contains(pHead2)) {
return pHead2;
}
pHead2 = pHead2.next;
}
return null;
}
}
解法二:
思想与链表中倒数第K个节点这道题目有点像。先遍历一边链表一,记录下长度m,再遍历链表二,记录下长度n。假设m> n。
若链表一和二有公共节点,则从第一个公共节点开始到末点均为公共点。那么让链表一从第(m-n+1)个点,链表二从第一个点开始同时跑,二者相遇的点便是公共点。即使链表一和链表二没有公共点,那么二者最终相遇于两个null节点,返回null。
public class Solution {
public static ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int m = 0, n = 0;
ListNode p1 = pHead1, p2 = pHead2;
while(p1 != null) {
m++;
p1 = p1.next;
}
while(p2 != null) {
n++;
p2 = p2.next;
}
for(int i = 0; i < m - n; i++) {
if(m > n)
pHead1 = pHead1.next;
else
pHead2 = pHead2.next;
}
while(pHead1 != pHead2) {
pHead1 = pHead1.next;
pHead2 = pHead2.next;
}
return pHead1;
}
}
解法三:
这种方法思路与方法二很像,但是更巧妙。假设链表一长度为m,链表二长度为n,这两个链表有公共点,公共长度为k。
设指针p1指向链表一的头,p2指向链表2的头。
p1遍历完链表一后跳转指向链表二的头,再对链表二进行遍历直到末尾。
p2遍历完链表二后跳转指向链表一的头,再对链表一进行遍历直到末尾。
则,p1走过的路程为m+n-k,p2走过的路程为m+n-k,二者相同。
现在我们让p1和p2同时出发,每次同时指向下一个节点。则二者肯定同时遍历完链表一和链表二,相遇于null。
我们通过图片来演示过程:
上边为链表一,下边为链表二,白色箭头为p1,黑色箭头为p2
(1)p1与p2均指向各自的链表头
[图片上传中...(image-3a3fa-1561189902540-4)]
(2)p1与p2同时移动

(3)p2移动到末尾后跳转到链表一的头,p1和p2依旧同时移动

(4)当p1也移动到末尾并跳转到链表二的头部时,此时p1与p2并列前行。因为二者要经过的总距离均为m+n-k,必定同时到达终点,##定是并列前行。

(5)p1与p2第一次相遇的点便为公共点。若无公共点,则相遇于两个null节点。

网友评论