2.07链表相交
给你两个单链表的头节点 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 * 104 1 <= Node.val <=
105 0 <= skipA <= m 0 <= skipB <= n 如果 listA 和 listB 没有交点,intersectVal
为 0 如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] ==
listB[skipB + 1]
思路一
借鉴大神操作,追击相遇问题
太巧妙了
如果两个链表相交,两个指针最终会在相交节点相遇,因为它们遍历的总长度是相同的(先走完一个链表,再走另一个链表的剩余部分)。
如果两个链表不相交,两个指针最终会同时指向 null,这是因为它们走过的路径长度相同,但是都走完了两个链表,最后都指向了 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) {
ListNode A = headA;
ListNode B = headB;
//当A B不相遇时
while(A != B){
//A如果不为空,A向后走否则将A指向B链首
A = A != null ? A.next : headB;
//B如果不为空,B向后走,否则将B指向A的链首
B = B != null ? B.next : headA;
}
//返回重合点
return A;
}
}
思路二
比较麻烦,但是更加容易想到哦
- 找出A ,B链表的长度差并将两条链表尾部对齐
- 假设A长B短,那么从B的开头,A的(lenA - lenB)位置开始遍历
- AB同时向后移动,直到AB找到相同的后缀
- 找不到就直接返回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) {
//找出A ,B链表的长度差并将两条链表尾部对齐
//假设A长B短,那么从B的开头开始遍历
//AB同时向后移动,直到AB找到相同的后缀
//找不到就直接返回null
ListNode A = headA, B = headB;
int lenA = 0 , lenB = 0;
//寻找A的长度
while(A != null){
lenA ++;
A = A.next;
}
//寻找B的长度
while (B != null){
lenB ++;
B = B.next;
}
//重置A, B指针为初始位置
A = headA;
B = headB;
//让A为最长链表的头,lenA为其长度
if(lenB > lenA){
//交换A ,B指针位置(交换三步走)
ListNode tmpNode = A;
A = B;
B = tmpNode;
//交换lenA ,lenB
int tmp = lenA;
lenA = lenB;
lenB = tmp;
}
//求A B长度差
int gap = lenA - lenB;
//让A和B在同一起点上
while (gap > 0){
A = A.next;
--gap;
}
//当A不为空时,遇到相同则返回
while (A != null){
if(A == B){
return A;
}
A = A.next;
B = B.next;
}
return null;
}
}