编写一个程序,找到两个单链表相交的起始节点。
例如,下面的两个链表:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
在节点 c1 开始相交。
注意:
- 如果两个链表没有交点,返回
null
. - 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
- 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
致谢:
特别感谢 @stellari 添加此问题并创建所有测试用例。
//章节 - 链表 //二、双指针技巧 //3.相交链表 /* 算法思想:一个常规方法, 如果两个链长度相同的话,那么对应的一个个比下去就能找到,所以只需要把长链表变短即可。具体算法为:分别遍历两个链表,得到分别对应的长度。然后求长度的差值,把较长的那个链表向后移动这个差值的个数,然后一一比较即可。 */ //算法实现: /** * 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) { if (headA == NULL || headB == NULL) return NULL; ListNode *p = headA; ListNode *q = headB; int lenA = 0, lenB = 0; while (p->next != NULL) { p = p->next; lenA++; } while (q->next != NULL) { q = q->next; lenB++; } if (q != p) //若最后一个结点都不相同则肯定没有相交 return NULL; int x = abs(lenA - lenB); if (lenA > lenB) { for (int i = 0; i < x; i++) headA = headA->next; } else { for (int i = 0; i < x; i++) headB = headB->next; } while (headA != headB) { headA = headA->next; headB = headB->next; } return headA; } }; */ /* 算法思想:一个巧方法, 虽然题目中强调了链表中不存在环,但是可以用环的思想来做,我们让两条链表分别从各自的开头开始往后遍历,当其中一条遍历到末尾时,我们跳到另一个条链表的开头继续遍历。两个指针最终会相等,而且只有两种情况,一种情况是在交点处相遇,另一种情况是在各自的末尾的空节点处相等。为什么一定会相等呢,因为两个指针走过的路程相同,是两个链表的长度之和,所以一定会相等。 */ //算法实现: class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { if (headA == NULL || headB == NULL) return NULL; ListNode *a = headA, *b = headB; while (a != b) { a = a ? a->next : headB; b = b ? b->next : headA; } return a; } };