可以用来找出两个链表的交点
题目 力扣160
核心思想
设 A 的长度为 a + c,B 的长度为 b + c,其中 c 为尾部公共部分长度,
可知 a + c + b = b + c + a。
当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;
同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。
这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。
如果不存在交点,那么 a + b = b + a 他们最后的结果都是NULL,因为相等而跳出循环
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *a = headA;
ListNode *b = headB;
while(a != b)
{
a = a == NULL? headB : a->next;
b = b == NULL? headA : b->next;
}
return b;
}
};
为什么要用中间变量来遍历链表呢? 而不是
while(headA != headB)
{
headA = headA == NULL? headB : headA->next;
headB = headB == NULL? headA : headB->next;
}
return headB;
当然,我将提供一个特例来说明为什么直接在头指针`headA`和`headB`上操作可能导致错误。
考虑以下两个链表:
```
链表A: 1 -> 2 -> 3
\
5 -> 6 -> 7
/
链表B: 4 -> 5
```
这两个链表在节点5处相交。我们来看看按照您提供的代码逻辑会发生什么:
1. 开始时,`headA`指向1,`headB`指向4。
2. 没有立即找到交点,所以进入循环。`headA`变为2,`headB`变为5。
3. `headA`变为3,`headB`变为6。
4. `headA`变为5,`headB`变为7。
5. `headA`变为6,`headB`因为`headB == NULL`,按照您的代码,
应该变为`headA`,但这时`headA`还没有更新为`NULL`,
所以`headB`实际上会跳到6的下一个节点,即7的下一个节点,这里出现了逻辑错误。
在第5步中,您的代码逻辑就已经出现了问题,因为`headB`应该跳转到链表A的头部,
但是由于`headA`和`headB`的更新是同时进行的,
`headB = headB == NULL ? headA : headB->next;`
这行代码在`headB`需要跳转到链表A的头部时,并不能正确执行,
因为此时`headA`不是`NULL`,而是链表A中的某个有效节点。
正确的逻辑是,在任一指针(`headA`或`headB`)达到其链表末尾时,
将其重定向到另一个链表的头部,而不是立即重定向到当前链表的下一个节点。
这样,两个指针最终将在第二次遍历时在交点相遇,
或者如果没有交点,它们会同时到达各自链表的末尾(`NULL`),从而结束循环。
因此,使用两个独立的指针变量(如`pointerA`和`pointerB`)是保证逻辑正确性的关键。