题目
Write a program to find the node at which the intersection of two singly linked lists begins. For example, the following two linked lists, they 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.
思路
如果没有记错,这道题若干年前在《编程之美》上做过,当时花了很长时间也没有想到符合“run in O(n) time and use only O(1) memory”的算法。
这里有一个容易被我们忽略的常识,一旦两条链表交叉,则这个节点之后的所有节点都是两个链表共有的,然而,这对下面代码用到的算法并没有什么卵用。
如果链表能倒着遍历,我们是能很好找到第一个共同节点的。让两个指针分别指向两条链表的尾端,如果不同,则两条链表没有共同节点;如果相同,则均向前遍历,直到两个指针指向不同的节点,则上一个节点即为第一个共同节点。
现在我们只能向后遍历,怎么办呢?先让我们思考一个问题:如果两条链表均从后向前从1开始标号,如下图,链表A的7号节点可能和链表B的5号节点是同一个节点吗?不可能!如果它们是同一个节点的话,那么A的7号之后的6个节点和B的5号之后的4个节点是一一对应的关系(其实,上面的“常识”在这里还是有点用的),但是……个数都对不上,你给我开玩笑呢?所以,A、B的共同节点只可能存在于A、B相同标号的节点上。
这样,在下图中,我们逐一对比A的5号节点和B的5号节点是不是同一个节点;A的4号节点和B的4号节点是不是同一个节点……
代码
/**
* 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 * ret;
ListNode * pA = headA;
ListNode * pB = headB;
int numA = 0;
int numB = 0;
while (pA != NULL)
{
++numA;
pA = pA->next;
}
while (pB != NULL)
{
++numB;
pB = pB->next;
}
pA = headA;
pB = headB;
if (numA > numB)
{
for (int i =0; i < numA - numB; ++i)
{
pA = pA->next;
}
}
else
{
for (int i =0; i < numB - numA; ++i)
{
pB = pB->next;
}
}
while(pA != pB)
{
pA = pA->next;
pB = pB->next;
}
return pA;
}
};
总结
正正反反,傻傻分不清楚。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。