相交链表
题目
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
示例
示例 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。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
力扣题解
// 标记法
1、分别定义 `a、b` ,并进行赋值
2、循环对其中一条链表每个元素做一个 `标记`
3、循环第二条链表,如果相交,那么可以在某个位置找到 `标记`
力扣较好题解
// 双指针法
1、分别定义 `a、b` ,并进行赋值
2、
若 `a、b` 存在相交节点,则 `a、b` 在相交节点后的是 `同一条链表`
那么应该将 `a、b` 向右对齐,而后 `从左往右` 开始对比 a 和 b
但是 a 和 b 不一定长度一样,所以,我们可以将 `a、b` 组合成 `ab` 和 `ba`
以 `a` 开头 链接 `b` 得到 `a -> b`,即链表 `ab`
以 `b` 开头 链接 `a` 得到 `b -> a`, 即链表 `ba`
`ab` 和 `ba` 长度相等, `从左往右` 对比,若相等,那么该元素就是 `相交节点`
同时间分别遍历 `ab、ba` ,将在某个节点找到相同的元素
a: 1 - 3 - 5 - 7 - 9
b: 2 - 6 - 7 - 9
a - b : 1 - 3 - 5 - 7 - 9 - 2 - 6 - 7 - 9
| a | | b |
b - a : 2 - 6 - 7 - 9 - 1 - 3 - 5 - 7 - 9
| b | | a |
3、循环对比
若 `a === b`
若都为 `null` 说明 `ab` 和 `ba` 都遍历到结尾了,都是 `null` ,返回 `null`
若不为 `null` ,且相等,说明找到 `相交的节点` ,返回该节点
若 `a !=== b`
a, b 取各自的下一个值
若下一个值不存在,则赋值为 另外一个链表的开头(即上面所说的链表相加)
题解
力扣题解
// 用时一般,内存消耗较多
执行用时: 96 ms
内存消耗: 44.2 MB
// 标记法
let getIntersectionNode = function(headA, headB) {
// 分别定义 a,b,并进行赋值
let [a, b] = [headA, headB];
// 循环对其中一条链表每个元素做一个标记
while(a) {
a.flag = 1
a = a.next
}
// 循环第二条链表,如果相交,那么可以在某个位置找到标记
while(b) {
if (b.flag) return b
b = b.next
}
return null
}
力扣较好题解
// 用时较好,内存消耗较好
执行用时: 88 ms
内存消耗: 42.3 MB
// 双指针法
let getIntersectionNode = function(headA, headB) {
// 分别定义 a,b,并进行赋值
let [a, b] = [headA, headB];
// 双指针法:
// 两条链表 a,b:
// 若 a、b 存在相交节点,则 a、b 在相交节点后的是同一条链表
// 那么应该将 a b 向右对齐,而后从左往右开始对比 a 和 b
// 但是 a 和 b 不一定长度一样,所以,我们可以将 a、b 组合成 ab 和 ba
// 以 a 开头 链接 b 得到 a -> b,即链表 ab
// 以 b 开头 链接 a 得到 b -> a, 即链表 ba
// ab 和 ba 长度相等,从左往右对比,若相等,那么该元素就是相交节点
// 同时间分别遍历 ab、ba,将在某个节点找到相同的元素
// a: 1 - 3 - 5 - 7 - 9
// b: 2 - 6 - 7 - 9
// a - b : 1 - 3 - 5 - 7 - 9 - 2 - 6 - 7 - 9
// | a | | b |
// b - a : 2 - 6 - 7 - 9 - 1 - 3 - 5 - 7 - 9
// | b | | a |
// 持续循环
while(true) {
// 直到 a === b
// 若都为 null 说明 a 和 b 都遍历到结尾了,都是 null,返回 null
// 若不为 null ,且相等,说明找到相交的节点,返回该节点
// 注意此处要加分号隔离下面的语句
if (a === b) return a;
// 若不相等
// a, b 取各自的下一个值
// 若下一个值不存在,则赋值为 另外一个链表的开头
[a, b] = [a ? a.next : headB, b ? b.next : headA];
}
}