题目描述
- 输入两个链表,找出它们的第一个公共结点。
- 地址:牛客链接
问题分析
- 首先,要明确一点,牛客上的测试用例中这两条链表是不存在环的。
- 然后,明确:若两条链表相交,那么从它们的相交点开始,到两链的末尾,都是相同的。不要异想天开,认为存在那种交叉的情况,next指针只有一个,不可能交叉。只可能是 “丫” 字形状。
- 用额外空间
- 先遍历第一条链表,将所有节点存入HashSet中,然后遍历第二条链表节点,若set中存在当前节点,则直接返回,这便是第一个公共节点
时间复杂度:O(M+N) - 也可以用栈的LIFO特性,遍历两条链表,分为存入两个栈中,然后如果两栈栈顶相等,则都出栈,并用res(初始化为null)记录出栈元素,循环,直至某一栈为空或者栈顶元素不等,res便是第一个公共节点。
- 不用额外空间
- 计算两链表长度,让长链表先走长度差 diff 步,然后长短链表一起走,直至遇到相同节点为止
注意,在统计长度的时候,同时记录链表尾部,先判断两者尾部是否相同,若不同,那么肯定没有公共节点。 - 另一种方法实在是奇淫技巧!!!,定义两指针,p1,p2,两指针一起走,p1先走链表1,再走链表2,p2先走链表2,再走链表1.直至p1 == p2,才跳出循环,返回p1
- 这个方法避免了统计链表长度,利用两链表“拼接”的形式,自动形成了 链表长度差,达到了上面方法的效果。例如 12345-345 与345-12345 。或者 1345 - 2345 与2345 - 1345 。这个法有点找单链表中倒数第K个节点的意思。
- 并且,如果两链表长度相同,但无公共节点时,会在p1走完第一条链,p2走完第二条链,便都为null,跳出循环。若长度不等,但是两链加一起长度相等啊,会在p1走完第2条链,p2走完第一条链,都为null,跳出循环
- 所以,时间复杂度为O(M + N)
经验教训
- 注意以上方法都是要求两链无环
- 链表题两大套路
- 注意不用额外空间的两种做法
代码实现
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if (pHead1 == null || pHead2 == null) {
return null;
}
HashSet<ListNode> set = new HashSet<>();
ListNode curNode = pHead1;
while (curNode != null) {
set.add(curNode);
curNode = curNode.next;
}
curNode = pHead2;
while (curNode != null) {
if (set.contains(curNode)) {
return curNode;
}
curNode = curNode.next;
}
return null;
}
public ListNode FindFirstCommonNode2(ListNode pHead1, ListNode pHead2) {
if (pHead1 == null || pHead2 == null) {
return null;
}
ListNode cur1 = pHead1;
ListNode cur2 = pHead2;
ListNode tail1 = null;
ListNode tail2 = null;
int length1 = 0;
int length2 = 0;
while (cur1 != null) {
length1++;
tail1 = cur1;
cur1 = cur1.next;
}
while (cur2 != null) {
length2++;
tail2 = cur2;
cur2 = cur2.next;
}
if (tail1 != tail2) {
return null;
}
cur1 = pHead1;
cur2 = pHead2;
if (length1 >= length2) {
int diff = length1 - length2;
while (diff > 0) {
cur1 = cur1.next;
diff--;
}
}else {
int diff = length2 - length1;
while(diff > 0) {
cur2 = cur2.next;
diff--;
}
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if (pHead1 == null || pHead2 == null) {
return null;
}
ListNode p1 = pHead1;
ListNode p2 = pHead2;
while (p1 != p2) {
p1 = p1 == null ? pHead2 : p1.next;
p2 = p2 == null ? pHead1 : p2.next;
}
return p1;
}