寻找链表的第一个公共交叉点
由于链表的特殊的结构,如果链表存在交叉点,那么一定是Y类型的;
方式一 hashSet的方式
1.首先将链表A中的所有的节点加入到HashSet中
2.遍历链表B中所有的节点,如果节点在在hashSet中,直接返回节点(这是由链表的性质决定)
如果所有B中的节点都不在于hashSet中,那么返回null;
private ListNode getIntersectionNode(ListNode headA, ListNode headB) {
HashSet<ListNode> res = new HashSet<>();
ListNode cur = headA;
while (cur != null) {
res.add(cur);
cur = cur.next;
}
cur = headB;
while (cur != null) {
if (res.contains(cur)) {
return cur;
}
cur = cur.next;
}
return null;
}
方式二 先走k步的方式
思想:如果两个链表相交,则最后一个结点一定 是共有的,肯定是从某个节点开始相遇,然后一起走到终点;
1.可以分别遍历2个链表,记录其最后一个 结点和链表长度
2.若2个链表最后一个结点相等,则 相交,否则不相交
3.用指针p1指向较长的那个链表,p2指向 较短的那个链表
4.p1先向后移动|L1-L2|步,然后p1 和p2同时向后移动,每移动一步比较p1和p2是否相 等,当二者相等时,其指向的结点即为交点
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null) return null;
int count = 0;
ListNode curA = headA,curB = headB;
// 循环之后,curA指向了headA链表的末尾
while(curA.next != null) {
count++;
curA = curA.next;
}
// 循环之后curA指向headB链表的末尾
while(curB.next != null){
count--;
curB = curB.next;
}
//末尾节点不想等,不可能存在交叉
if(curA != curB) return null;
// curA 来记录比较长的链表
curA = count > 0 ? headA : headB;
curB = curA == headA ? headB : headA;
count = Math.abs(count);
// 较长的链表先走count步
while(count > 0) {
count--;
curA = curA.next;
}
// curA和curB同时向前走,直到curA等于curB
while(curA != curB) {
curA = curA.next;
curB = curB.next;
}
return curA;
}
方式三 奇思妙想的方式(null节点公共节点)
1.这个方式是在第二种方式上衍生出来,只是更加巧妙;
原理:
1.首先是较短的指针到达链表的末尾,从而指向较长链表
2.较长链表到达链表末尾的时候,指向较短链表,
3.重点来了,指针在较长链表的走过的节点数刚刚好是两个链表的长度差
总共经历了两轮循环
第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
第二轮: 有交点就返回, 无交点就是各走了两条指针的长度
不会陷入到死循环么?
如果不存在交叉,会同时指向null
public ListNode getIntersectionNodeA(ListNode headA, ListNode headB) {
if(headA == null || headB == null) {
return null;
}
ListNode pA = headA,pB = headB;
while(pA != pB){
pA = pA == null ? pB : pA.next;
pB = pB == null ? pA : pB.next;
}
return pA;
}
欢迎小伙伴评论交流
本文总结了三种寻找链表第一个公共交叉点的方法:利用HashSet、先走k步以及通过null节点。方式一通过存储链表A的节点,再遍历B查找公共节点;方式二比较链表长度,然后同步移动指针寻找交点;方式三则是巧妙地利用长度差进行两次循环查找。若无交叉点,指针最终会同时指向null。
1286

被折叠的 条评论
为什么被折叠?



