^ _ ^ 有趣都藏在无聊的日子里,所以保持热爱 @悄悄努力的人er
题目描述:160. 相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。 在 A 中,相交节点前有 2个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3,skipB = 1
输出:Intersected at ‘2’
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB= 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。 由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 这两个链表不相交,因此返回 null 。
提示:
- listA 中节点数目为 m
- listB 中节点数目为 n
- 0 <= m, n <= 3 * 10^4
- 1 <= Node.val <= 10^5
- 0 <= skipA <= m
- 0 <= skipB <= n
- 如果 listA 和 listB没有交点,intersectVal 为 0
- 如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]
思路描述:
思路1:哈希表
若两个链表中有空链表,则这两个链表定不会相交。
在两链表都不为空的情况下,
- 创建哈希表,用于存储链表节点
- 遍历链表headA,获取每个节点并存入哈希表。(此时,获取的该节点为以当前节点的为头结点的链表。因为当前节点的next方法,可以使一个节点代表一条链表)
如:listA = [4,1,8,4,5] 。则存入哈希表中的依次为:4、1、8、4、5
其中8代表 [ 8 , 4 , 5 ] - 遍历链表headB,获取每个节点并在哈希表中查找是否含有该节点,若含有,说明当前节点以及之后节点元素都一样,返回该节点
- 遍历结束,返回null,说明未找到相交链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//若有链表为空,则不会相交
if(headA==null || headB==null){
return null;
}
Set<ListNode> set=new HashSet<ListNode>();
ListNode curr=headA;
//遍历headA,将每个结点存入集合
while(curr!=null){
set.add(curr);
curr=curr.next;
}
curr=headB;
//遍历headB,在集合中查找是否有当前结点
while(curr!=null){
if(set.contains(curr)){
return curr;
}
curr=curr.next;
}
return null;
}
}
思路2:(双指针)
同样,若两个链表中有空链表,则这两个链表定不会相交。
在两链表都不为空的情况下,
我们发现,若给headA 后面加上headB,headB后面加上headA,此时两链表长度相同,并且在有相交节点情况下,后面几个元素一定相同;
则很容易可以找到相交节点;
例如示例1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
如按上述描述:
listA = 4 --> 1 --> 8 --> 4 --> 5 --> 5 --> 0 --> 1 --> 8 --> 4 --> 5
listB = 5 --> 0 --> 1 --> 8 --> 4 --> 5 --> 4 --> 1 --> 8 --> 4 --> 5
明白了这个原理,我们可以这样实现:定义两个指针 i , j ;
- 开始时,指针 i 指向headA ,指针 j 指向headB,开始遍历两个链表
- 当 i 不为null时,更新 i 为 i.next ;当 j 不为null时,更新 j 为 j.next ;
- 当 i 为null时,更新 i 为 headB ;当 j 为null时,更新 j 为 headA ;
- 当 i=j 时,分两种情况,1》同时为null,2》找到相交节点,不管那种情况我们只需要返回当前节点即可;
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//若有链表为空,则不会相交
if(headA==null || headB==null){
return null;
}
ListNode i=headA,j=headB;
while(i!=j){
if(i!=null&&j!=null){
i=i.next;
j=j.next;
}
if(i==null&&j!=null){
i=headB;
j=j.next;
}
if(i!=null&&j==null){
i=i.next;
j=headA;
}
}
return i;
}
}
思路2优化代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//若有链表为空,则不会相交
if(headA==null || headB==null){
return null;
}
ListNode i=headA,j=headB;
while(i!=j){
i=i==null?headB:i.next;
j=j==null?headA:j.next;
}
return i;
}
}
最后,附上题目链接:
https://leetcode-cn.com/problems/intersection-of-two-linked-lists/