链表相交
一、题目
给定两个(单向)链表,判定它们是否相交并返回交点。请注意相交的定义基于节点的引用,而不是基于节点的值。换句话说,如果一个链表的第k个节点与另一个链表的第j个节点是同一节点(引用完全相同),则这两个链表相交。
二、示例
输入: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、暴力法
双重循环,时间复杂度O(n^2)
2、求长度
如果存在交点,则从交点到链表末尾各个节点都相同,长度相同。因此,可以对暴力法做出相应改进,不用从头到尾一个节点一个节点的判断。
因为相交点到结尾长度都是一样,而两者相交长度小于两者之间的较短长度 len,所以可以直接从离末尾长len的节点开始判断。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int len1 = 0;
int len2 = 0;
ListNode temp = headA;
while(temp != null) {
len1++;
temp = temp.next;
}
temp = headB;
while(temp != null) {
len2++;
temp = temp.next;
}
ListNode temp1 = (len1 > len2 ? headA : headB);
temp = (len1 > len2 ? headB : headA);
for(int i = 0; i < Math.abs(len1 - len2); i++) {
temp1 = temp1.next;
}
for(int i = 0; i < Math.min(len1, len2); i++) {
if(temp1 == temp) {
return temp1;
}
else {
temp1 = temp1.next;
temp = temp.next;
}
}
return null;
}
3、双指针
设链表A的长度为a,链表B的长度为b,A到相交结点的距离为c,B到相交节点的距离为d,显然可以得到两者相交链表的长度:a - c = b - d, 变换一下式子得到:a + d = b + c。
我们用一个指针从链表A出发,到末尾后就从B出发,用另一个指针从B出发,到末尾后从A出发,由于上面的公式,当前一个指针走了a+d步数时,后一个指针走了b+c,两步数相等,即走到了相交节点。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//tempA和tempB我们可以认为是A,B两个指针
ListNode tempA = headA;
ListNode tempB = headB;
while (tempA != tempB) {
//如果指针tempA不为空,tempA就往后移一步。
//如果指针tempA为空,就让指针tempA指向headB(注意这里是headB不是tempB)
tempA = tempA == null ? headB : tempA.next;
//指针tempB同上
tempB = tempB == null ? headA : tempB.next;
}
//tempA要么是空,要么是两链表的交点
return tempA;
}