牛客:JZ36 两个链表的第一个公共结点
1.4.1题目
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表:
![image-20210930141259533](https://i-blog.csdnimg.cn/blog_migrate/365171632f0c188a9a25630bcd144b6d.png)
在节点 c1 开始相交。
示例 1:
![image-20210930141329672](https://i-blog.csdnimg.cn/blog_migrate/ba08c610d039c82da5653fc10498f868.png)
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
1.4.2方法一:利用HashSet不可重复特点
思路:先将一个链表所有的节点全部添加到set中,再将另一个链表的节点往set中添加,如果两个链表有公共节点则第二个节点添加的时候返回false
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> set = new HashSet(); //存放链表节点中的1值
ListNode a = headA;
ListNode b = headB;
while(a != null){ //现将a链表放入set
set.add(a);
a = a.next;
}
while(b != null){ //将b链表的节点放入set中
boolean flog = set.add(b);
if(flog == false){
return b;
}
b = b.next;
}
return null;
}
}
时间复杂度O(N),空间复杂度O(m+n)
1.4.3方法二:双指针+数学公式
![image-20210930140536878](https://i-blog.csdnimg.cn/blog_migrate/9eb80fb4e4dc254e2d675ead7193131c.png)
-
指针 A 先遍历完链表 headA ,再开始遍历链表 headB ,当走到 node 时,共走步数为:
a + (b - c) -
指针 B 先遍历完链表 headB ,再开始遍历链表 headA ,当走到 node 时,共走步数为:
b + (a - c) -
如下式所示,此时指针 A , B 重合,并有两种情况:
a + (b - c) = b + (a - c)
- 若两链表 有 公共尾部 (即 c > 0 ) :指针 A , B 同时指向「第一个公共节点」node 。
- 若两链表 无 公共尾部 (即 c = 0) :指针 A , B 同时指向 null 。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
if(headA == null || headB == null){
return null;
}
while(curA != curB){
curA = (curA == null) ? headB : curA.next;
curB = (curB == null) ? headA : curB.next;
}
return curA;
}
}
时间复杂度O(N),空间复杂度O(1)