Write a program to find the node at which the intersection of two singly linked lists begins.
For example, the following two linked lists:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
begin to intersect at node c1.
Notes:
- If the two linked lists have no intersection at all, return
null
. - The linked lists must retain their original structure after the function returns.
- You may assume there are no cycles anywhere in the entire linked structure.
- Your code should preferably run in O(n) time and use only O(1) memory.
算法一:
设立2个指针,各指向一个链表头部。
同时向前,直到找到相同节点。
当指针遍历到链表尾部时,该指针重新指向另一链表的头部。
算法能工作的原理为:
设两者有交点。
A 链表的节点数为 m + c
B 链表的节点数为 n + c
其中, c为 相交节点数。 即共享的节点数。
m, n则为链表各自不节享节数。
则有 m + c + n == n + c + m
此式意义为:
设p1 初始指向A链表,p2初始指向B链表。
当p1 经过遍历完A链表(m+c个节点),并且遍历B链表n个节点后,p1来到交点处。
而此时p2 也刚好到了交点处。即遍历完B链表(n+c个节点), 且遍历A链表m个节点。
故能找到交点。
下面代码,当不存在交点时,如何退出循环的呢。
p1在遍历完A链表,并遍历完B链表后,此时,它到B链表末尾;
而此时p2,遍历完B链表,也一定处在A链表末尾; 因为两个指针都完成把两个链表同时遍历一次。
即此时,p1和p2指针同时为空。
所以在两个链表不存在交点时,遍历的结点数为两个链表之和。
另外,如果两个链表长度相等情况下,将会提前结束。即只需遍历完一个链表长度。
下面这行代码,是处理交点不存在时的关键:
if (p1 == p2)
return p1;
在leetcode 上实际执行时间为52ms。
/**
* 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 || !headB)
return NULL;
ListNode *p1 = headA;
ListNode *p2 = headB;
while (p1 != p2) {
p1 = p1->next;
p2 = p2->next;
if (p1 == p2)
return p1;
if (!p1) p1 = headB;
if (!p2) p2 = headA;
}
return p1;
}
};
算法来源:
https://leetcode.com/discuss/17278/accepted-shortest-explaining-algorithm-comments-improvements
算法二
此算法为较常见的思路:
1. 先统计两者链表的长度。
2. 设立2指针,分表指向两个链表。 并使较长的链表,先行步进指针。步进的步数,为长度差值。
3. 然后作比较,并同时步进2个针指针。
此算法在leetcode上实际执行时间为56ms。
对比起来,此算法的时间复杂度,并不差于算法一。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (!headA || !headB)
return NULL;
int sizeA = 0;
ListNode *p = headA;
while (p) {
p = p->next;
++sizeA;
}
int sizeB = 0;
p = headB;
while (p) {
p = p->next;
++sizeB;
}
while (sizeA > sizeB) {
headA = headA->next;
--sizeA;
}
while (sizeB > sizeA) {
headB = headB->next;
--sizeB;
}
while (headA && headA != headB) {
headA = headA->next;
headB = headB->next;
}
return headA;
}
};