题目概述(简单难度)
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入: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 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Reference of the node with value = 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。
注意:
1:如果两个链表没有交点,返回 null.
2:在返回结果后,两个链表仍须保持原有的结构。
3:可假定整个链表结构中没有循环。
4:程序尽量满足 O(n)时间复杂度,且仅用 O(1) 内存。
附上leetcode链接:
点击此处进入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(headA==null||headB==null){ 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)
2:此算法的思路比较巧妙,需要大家细细斟酌.