算法通关村第一关|两个链表第一个公共子节点
题目为剑指 Offer 52. 两个链表的第一个公共节点
解法一:集合
先将一个链表元素全部存入集合,一边遍历第二个链表一边去集合中比较,如果存在交点一定能检测出来
public ListNode findFirstCommonNodeBySet(ListNode headA, ListNode headB) {
Set<ListNode> set = new HashSet<>();
while (headA != null) {
set.add(headA);
headA = headA.next;
}
while (headB != null) {
if (set.contains(headB)) {
return headB;
}
headB = headB.next;
}
return null;
}
解法二:栈
将两个链表元素压入两个不同的栈中,然后分别出栈,如果相等继续出栈,直到找到最晚出栈的一组
public ListNode findFirstCommonNodeByStack(ListNode headA, ListNode headB) {
Stack<ListNode> stackA = new Stack<>();
Stack<ListNode> stackB = new Stack<>();
while (headA != null) {
stackA.push(headA);
headA = headA.next;
}
while (headB != null) {
stackA.push(headB);
headB = headB.next;
}
ListNode temp = null;
while (stackA.size() > 0 && stackB.size() > 0) {
if (stackA.peek() == stackB.peek()) {
temp = stackA.pop();
stackB.pop();
} else {
break;
}
}
return temp;
}
解法三:拼接两个字符串
有如下两个链表:
A:a1-a2-c1-c2-c3
B:b1-b2-b3-c1-c2-c3
分别以AB和BA拼接后
AB:a1-a2-c1-c2-c3-b1-b2-b3-c1-c2-c3
BA:b1-b2-b3-c1-c2-c3-a1-a2-c1-c2-c3
可以看到从最后一个c1开始两个链表变成一样了,因此c1就是所要找的交点
图片:
假设AB有交点,我们可以以交点为中心,将AB两个链表分成左右两部分:
LA: a1-a2 RA: c2-c3 LB: b1-b2-b3 RB: c2-c3
RA和RB是一样的,这个时候分别遍历AB和BA从某个位置开始刚好就找到了交点
public ListNode findFirstCommonNodeByCombine(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode tempA = headA;
ListNode tempB = headB;
while (tempA != tempB) {
tempA = tempA.next;
tempB = tempB.next;
if (tempA != tempB) {
//一个链表遍历完了就跳到另一个链表接着遍历
if (tempA == null) {
tempA = headB;
}
if (tempB == null) {
tempB = headA;
}
}
}
return tempA;
}
解法四:差和双指针
先统计出两个链表的长度,当第一次链表遍历完后,长的链表先走|LA-LB|步,然后两个链表同时开始遍历,结点相同时就是所要找的交点
public ListNode findFirstCommonNodeBySub(ListNode headA , ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode currentA = headA;
ListNode currentB = headB;
int lenA = 0, lenB = 0;
//分别统计两个链表的长度
while (currentA != null) {
lenA++;
currentA = currentA.next;
}
while (currentB != null) {
lenB++;
currentB = currentB.next;
}
currentA = headA;
currentB = headB;
int sub = lenA > lenB ? lenA - lenB : lenB - lenA;
//长的先走sub步
if (lenA > lenB) {
int a = 0;
while (a < sub) {
currentA = currentA.next;
a++;
}
}
if (lenA < lenB) {
int a = 0;
while (a < sub) {
currentB = currentB.next;
a++;
}
}
//最后同时遍历两个链表
while (currentA != currentB) {
currentA = currentA.next;
currentB = currentB.next;
}
return currentA;
}