输入: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。
注意:
1:如果两个链表没有交点,返回 null.
2:在返回结果后,两个链表仍须保持原有的结构。
3:可假定整个链表结构中没有循环。
4:程序尽量满足 O(n)时间复杂度,且仅用 O(1) 内存。
附上leetcode链接:
附上牛客网链接
====================================================================
思路展现
寻找两个链表的第一个公共节点,很多同学会陷入一个误区当中,先来看一个示意图:
对于上面这个图来说,很多同学会误以为值域为33的这个节点就是我们两个链表的第一个公共节点,但是这是错误的,连我本人第一次做这道题的时候也是这么认为的,原因是链表的第一个公共节点一定是地址相同的两个节点,并不是值域相同的两个节点
,如下图所示:
可以看到这两个链表的第一个公共节点是值域为44的这个节点,因为从这个节点往后的每一个节点的地址都是相同的
知道了什么是链表的第一个公共节点后,下面我们来看如何通过代码寻找这个节点:
(1):既然是两个链表寻找第一个公共节点,那么就肯定需要遍历我们的两个链表,设置两个指针cur,cur1分别指向我们的链表的头节点,用于我们链表的遍历。
(2):现在开始寻找我们的公共节点,cur和cur1分别开始从链表的头节点开始遍历,在遍历前我们还需要考虑一个问题,就是在找到我们链表的第一个公共节点前,我们在遍历节点的时候会发现链表的长度不同,遍历的节点的个数会不相同,这是需要进行一些操作
,我们先来拿一个图进行举例:
可以看到在找到值域为44的这第一个公共节点前,我们的cur指针需要遍历三个节点才能找到,cur1指针需要遍历四个节点才可以找到,当cur和cur1同时遍历的时候,是永远不可能出现cur所指向的节点地址与cur1所指向的节点地址相同的情况的,所以在两个链表节点长度不相同的情况下,假设一个链表长度为lenA,一个链表长度为lenB,当lenA>lenB的时候,相当于第一个链表比第二个链表的长度要长,指向第一个链表的头节点的cur变量就需要先走lenA-lenB步,当lenA<lenB的时候,相当于第二个链表比第一个链表的长度要长,指向第二个链表的头节点的cur1变量就需要先走lenB-lenA步.较长的先走是为了确保两个链表能同时找到第一个公共节点,如果较长的链表中的遍历指针不先走那些差的步数,那么当同时向后遍历两个链表的时候是永远都找不到公共节点的.
(3):上述步骤完成后,当链表中含有公共节点的时候,我们的cur和cur1指针开始向后遍历,当找到链表的第一个公共节点后,返回cur即可,找不到返回null.
注意:我们的两个链表找到第一个公共节点前,它们的遍历指针cur和cur1一定是走了相同步数才找见的,如果判断出此时不能走相同步数,那么就必须使两个指针走相同的步数才可以,就需要我们使用(2)中的方法来实现
.
代码示例
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int length=0;
int length1=0;
ListNode cur=headA;
ListNode cur1=headB;
if(headAnull||headBnull){
return null;
}
while(cur!=null){
cur=cur.next;
length++;
}
while(cur1!=null){
cur1=cur1.next;
length1++;
}
//这个地方一定要指回来
cur=headA;
cur1=headB;
//为了让两个指针能走相同步数找到公共节点
while(length>length1){
cur=cur.next;
length1++;
}
while(length<length1){
cur1=cur1.next;
length++;
}
//开始寻找公共节点
while(cur!=cur1){
cur=cur.next;
cur1=cur1.next;
}
//返回第一个公共节点
return cur;
}
}
总结
1:此算法时间复杂度O(N)
,空间复杂度O(1)