题目
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
思路
1.差值步法
这个方法的思路为先定义两个指针nodeA,nodeB
,分别指向两条链表的头节点,再一人一步往后走,如果这两条链表有相交,则两个指针必定会相遇,若没有相遇则返回null
,说明两条链表没有相交。
但是上述情况是在两条链表长度相等的情况下,若这两条链表不相等怎么办呢?
可以先找到两条链表中较长的那条,让指向长链表的那个头指针先走它们两个链表的长度差值步数,然后两指针再一起往前走,若相遇则说明两条链表相交。
注意:只需要找到链表相交的起始节点即可,并不是找链表重合,二者概念不一样,相交只要有指针指向相同即可,而重合则是起点到终点所有内容相同。
java代码
class Solution{
public ListNode getIntersectionNode(ListNode headA,ListNode headB){
ListNode nodeA = headA;
ListNode nodeB = headB;
int lenA = 0,lenB = 0;
int gap = 0;
while(nodeA != null){// 求链表A的长度
lenA++;
nodeA = nodeA.next;
}
while(nodeB != null){// 求链表B的长度
lenB++;
nodeB = nodeB.next;
}
//再将两指针重新指向头节点,因为求长度的时候nodeA、nodeB走到了链表尾
nodeA = headA;
nodeB = headB;
//若链表A长,则nodeA先走长度差步
if(lenA > lenB){
gap = lenA - lenB;
while(gap-- > 0){
nodeA = nodeA.next;
}
}else{//若链表B长,则nodeB先走长度差步
gap = lenB - lenA;
while(gap-- > 0){
nodeB = nodeB.next;
}
}
while(nodeA != null && nodeB != null){//两指针同时走
if(nodeA == nodeB){//如果相遇,则代表相交,返回相交节点
return nodeA;
}
//否则继续往后判断
nodeA = nodeA.next;
nodeB = nodeB.next;
}
//当while循环遍历完时还没相遇,则不存在相交
return null;
}
}
2.双指针法
因为两条链表相交,所以会有一段公共长度(至少为1,哪怕后面不是完全重合),创建两个指针nodeA
和nodeB
分别指向链表A和链表B。
让他们分别循环往前各走一步,当nodeA
走完为空时,就让他前往链表B
的头节点;nodeB
也一样,当它走完时,让它前往A
链表的头节点。之后同样继续循环往前走,因为两条链表是相交的,则nodeA和nodeB必然会相遇(走的总长度相同,即A+B
的长度)。
因为两条链表相交时,分为三部分:c
部分是固定的,那么不管a
部分和b
部分谁长,走第二遍时,nodeA
走过的路程为a
部分长度加上b
部分长度;nodeB
走过的路程也为a部分长度加上b
部分长度。
java代码:
class Solution{
public ListNode getIntersectionNode(ListNode headA,ListNode headB){
if(headA == null || headB == null){//有一个链表为空都不可能相交
return null;
}
//创建新的变量指向当前头结点,方便移动,因为移动过程中是需要和头结点初始位置进行比较的,所以需要保持headA和headB不变
ListNode nodeA = headA;
ListNode nodeB = headB;
while(nodeA != nodeB){
if(nodeA == null){//A链表走完时,继续走B链表
nodeA = headB;
}else{
nodeA = nodeA.next;
}
if(nodeB == null){//B链表走完时,继续走A链表
nodeB = headA;
}else{
nodeB = nodeB.next;
}
}
return nodeA;
}
}
3.哈希集合法
若两条链表相交,则至少一个完全相同的节点,可以先遍历链表A
,将其所有的节点记录下来,然后遍历链表B
,若链表B
中存在一个及以上和链表A
中一样的节点,那么就说明这两条链表相交了,反之则未相交。
使用哈希集合来存储节点,遍历链表B
的节点时,依次判断该节点是否在哈希集合中
java代码:
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//定义一个哈希集合set
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;
}
}