题目
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.
解析
本题是求两个链表的交点,返回是交点的指针。因此想到了两个思路。
思路1:
(1)如果两个链表长度相等,从头开始遍历一直到结尾,如果有交点的话,headA == headB;如果没有交点,那遍历到最后headA == NULL, headB == NULL。
(2)如果两个链表长度不相等,根据例子中的情况,A链接短于B链接,因此,差出来的结点,先让B链表走完,这样就保证A链表和B链表相等,再走(1)就找到了。
思路2:
相对于思路1,思路2比较简练。
由于两个链表和总和是一定的,因此可以使用两个指针分别指向两个链表的头,依次遍历。假如A链表长度小于B链表,那么A链表先遍历完,那就跳转到B链表的头继续向后遍历,这时B链表还没有遍历完,B链表从该位置到结尾遍历的长度即是AB链表的差值结点,遍历完之后即跳转到A结点头,此时,跳转到B链表的指针也已经遍历完差点长度,A、B再继续遍历就相等了,走思路1中的(1)。
这两种思路从本质上是一样的,均需要把差值长度遍历完,只是思路1先遍历,思路2后遍历。
代码(C语言)
// 思路1
int getListLength(struct ListNode* head);
struct ListNode *getIntersectionNode(struct ListNode *headA,
struct ListNode *headB) {
if (!headA || !headB)
return NULL;
int listALength = getListLength(headA);
int listBLength = getListLength(headB);
int diff = listALength - listBLength;
// 先把长的链表走完
for (int i = 0; i < abs(diff); ++i) {
if (diff > 0)
headA = headA->next;
else
headB = headB->next;
}
// 找相同
while (headA && headB && headA != headB) {
headA = headA->next;
headB = headB->next;
}
return (headA && headB) ? headA : NULL;
}
int getListLength(struct ListNode* head) {
int length = 0;
while (head) {
++length;
head = head->next;
}
return length;
}
// 思路2
struct ListNode *getIntersectionNode2(struct ListNode *headA,
struct ListNode *headB) {
if (!headA || !headB)
return NULL;
struct ListNode* aNode = headA, * bNode = headB;
while (aNode != bNode) {
aNode = aNode ? aNode->next : headB;
bNode = bNode ? bNode->next : headA;
}
return aNode;
}