题目:输入两个链表,找出它们的第一个公共节点
方法一:哈希和集合
先将一个链表元素全部存到Map里,然后一边遍历第二个链表,一边检测Hash中是否存在当前结点,如果有交点,那么一定能检测出来。
/**
* 使用集合查找两个链表的第一个公共节点。
* @param headA 第一个链表的头节点。
* @param headB 第二个链表的头节点
* @return 第一个公共节点,如果不存在公共节点则返回null。
*/
public ListNode findFirstCommonNodeBySet(ListNode headA, ListNode headB) {
// 创建一个集合来存储链表A的节点
Set<ListNode> set = new HashSet<>();
// 遍历链表A,将每个节点添加到集合中
while (headA != null) {
set.add(headA);
headA = headA.next;
}
// 遍历链表B,检查每个节点是否存在于集合中
while (headB != null) {
if (set.contains(headB))
return headB; // 找到第一个公共节点
headB = headB.next;
}
return null; // 未找到公共节点
}
方法二:栈
需要用到两个空间为o(n)的栈,分别将两个链表的节点入两个栈,然后出栈,如果两个节点相等就继续出栈,直到找到最晚出栈的那组。
stack.push(a):将a元素入栈
stack.peek() :获取到栈顶部的元素
stack.pop() :从栈中移除并返回栈顶的元素
import java.util.Stack;
/**
* 使用栈查找两个链表的第一个公共节点。
* @param headA 第一个链表的头节点。
* @param headB 第二个链表的头节点
* @return 第一个公共节点,如果不存在公共节点则返回null。
*/
public ListNode findFirstCommonNodeByStack(ListNode headA, ListNode headB) {
// 创建两个栈,分别用于存储链表A和链表B的节点
Stack<ListNode> stackA = new Stack<>();
Stack<ListNode> stackB = new Stack<>();
// 遍历链表A,将每个节点压入栈中
while (headA != null) {
stackA.push(headA);
headA = headA.next;
}
// 遍历链表B,将每个节点压入栈中
while (headB != null) {
stackB.push(headB);
headB = headB.next;
}
// 从栈顶开始比较两个栈的节点,找到第一个不相等的节点即为分叉点,其前一个节点即为第一个公共节点
ListNode preNode = null;
while (!stackA.isEmpty() && !stackB.isEmpty()) {
if (stackA.peek() == stackB.peek()) {
preNode = stackA.pop();
stackB.pop();
} else {
break;
}
}
return preNode;
}
方法三:差和双指针
公共节点一定存在第一轮遍历,那么La的长度为L1,Lb的长度为L2,长度差的绝对值为|L1-L2|;第二轮遍历让长的先走|L1-L2|步,然后再同时向前走,直到找到相同节点即为公共节点。
public ListNode findFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1==null || pHead2==null){
return null;
}
ListNode current1=pHead1;
ListNode current2=pHead2;
int l1=0,l2=0;
//分别统计两个链表的长度
while(current1!=null){
current1=current1.next;
l1++;
}
while(current2!=null){
current2=current2.next;
l2++;
}
//将current的值变回头节点
current1=pHead1;
current2=pHead2;
int sub=l1>l2?l1-l2:l2-l1;
//长的先走sub步
if(l1>l2){
int a=0;
while(a<sub){
current1=current1.next;
a++;
}
}
if(l1<l2){
int a=0;
while(a<sub){
current2=current2.next;
a++;
}
}
//同时遍历两个链表,当值相当的时候就可以返回节点了
while(current2!=current1){
current2=current2.next;
current1=current1.next;
}
return current1;
}