题目

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null

图示两个链表在节点 c1 开始相交:
1.jpg
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须保持其原始结构

示例 1:
2.jpg

  1. 输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
  2. 输出:Intersected at '8'
  3. 解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
  4. 从各自的表头开始算起,链表 A [4,1,8,4,5],链表 B [5,0,1,8,4,5]。
  5. A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2:
3.jpg

  1. 输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
  2. 输出:Intersected at '2'
  3. 解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
  4. 从各自的表头开始算起,链表 A [0,9,1,2,4],链表 B [3,2,4]。
  5. A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:
4.jpg

  1. 输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
  2. 输出:null
  3. 解释:从各自的表头开始算起,链表 A [2,6,4],链表 B [1,5]。
  4. 由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA skipB 可以是任意值。
  5. 这两个链表不相交,因此返回 null

提示:

  • listA 中节点数目为 m
  • listB 中节点数目为 n
  • 0 <= m, n <= 3 * 104
  • 1 <= Node.val <= 10^5
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listAlistB 没有交点,intersectVal0
  • 如果 listAlistB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]

进阶:你能否设计一个时间复杂度 O(n) 、仅用 O(1) 内存的解决方案?

解题方法

双指针法

使用双指针分别计算两个链表的长度,随后将双指针重新移动至两个链表的头部,移动较长链表的指针使得两个指针末尾对齐。最后遍历链表寻找是否存在相交点。
时间复杂度O(m+n),空间复杂度O(1)
C++代码:

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode(int x) : val(x), next(NULL) {}
  7. * };
  8. */
  9. class Solution {
  10. public:
  11. ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
  12. int n_A = 0;
  13. int n_B = 0;
  14. ListNode* A = headA;
  15. ListNode* B = headB;
  16. while(A != NULL) {
  17. n_A++;
  18. A = A->next;
  19. }
  20. while(B != NULL) {
  21. n_B++;
  22. B = B->next;
  23. }
  24. A = headA;
  25. B = headB;
  26. if(n_A<n_B) {
  27. for(int i = 0; i<(n_B-n_A); i++) {
  28. B = B->next;
  29. }
  30. }
  31. else {
  32. for(int i = 0; i<(n_A-n_B); i++) {
  33. A = A->next;
  34. }
  35. }
  36. while(A != NULL) {
  37. if(A==B) return A;
  38. else {
  39. A = A->next;
  40. B = B->next;
  41. }
  42. }
  43. return NULL;
  44. }
  45. };

双指针法优化写法

无需计算两个链表的长度,将两个链表拼接即可实现循环中的末尾对齐
C++实现:

  1. class Solution {
  2. public:
  3. ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
  4. if (headA == nullptr || headB == nullptr) {
  5. return nullptr;
  6. }
  7. ListNode *pA = headA, *pB = headB;
  8. while (pA != pB) {
  9. pA = pA == nullptr ? headB : pA->next;
  10. pB = pB == nullptr ? headA : pB->next;
  11. }
  12. return pA;
  13. }
  14. };