面试算法(三十七)两个链表的第一个公共结点

来源:互联网 发布:全自动摇一摇软件 编辑:程序博客网 时间:2024/06/05 04:30

1、题目:输入两个链表,找出他们的第一个公共结点。

struct ListNode{     int  m_nKey;     ListNode*  m_pNext;};

解法一:

在第一个链表上顺序遍历每个结点,每遍历到一个结点的时候,在第二个链表上顺序遍历每个结点。如果在第二个链表上有一个结点和第一个链表上的结点一样,说明两个链表在这个结点上重合。若两个链表的长度分别为m和n,则时间复杂度为O(mn)。


解法二:

从链表结点定义看出,这两个链表是单向链表。若两个单向链表有公共结点,那么这两个链表从某一结点开始,他们的m_pNext都指向同一个结点。但由于每个结点只有一个m_pNext,因此从第一个公共结点开始,之后它们所有结点都是重合的,不可能再出现分叉。形状像一个Y。

1)可以发现,如果两个链表有公共结点,那么公共结点出现在两个链表的尾部。这时可以从两个链表的尾部开始比较,但单向链表只能从头部开始遍历,于是我们用栈解决。

2)分别把两个链表的结点放入两个栈里,这样两个链表的尾结点就位于栈的栈顶,这时比较两个栈顶的结点是否相同。如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同的结点。

此法需要两个辅助栈,若链表长度分别为m和n,那么空间复杂度是O(m+n),时间复杂度也是O(m+n)。


解法三:

首先遍历链表得到他们的长度,可以知道哪个比较长,以及长多少。第二次遍历时,在比较长的链表上先走若干步,接着再同时在两个链表上遍历,找到的第一个相同的结点就是他们的第一个公共结点。

此法时间复杂度是O(m+n),但是不需要辅助栈了。

ListNode* FindFirstCommonNode(ListNode *pHead1, ListNode *pHead2){//得到两个链表的长度unsigned int nLength1 = GetListLength(pHead1);unsigned int nLength2 = GetListLength(pHead2);int nLengthDif = nLength1 - nLength2;ListNode* pListHeadLong = pHead1;ListNode* pListHeadShort = pHead2;if(nLength2 > nLength1){pListHeadLong = pHead2;pListHeadShort = pHead1;nLengthDif = nLength2 - nLength1;}//先在长链表上走几步,再同时在两个链表上遍历for(int i=0; i<nLengthDif; ++i)pListHeadLong = pListHeadLong->m_pNext;while((pListHeadLong != NULL) && (pListHeadShort != NULL) && (pListHeadLong != pListHeadShort)){pListHeadLong = pListHeadLong->m_pNext;pListHeadShort = pListHeadShort->m_pNext;}//得到第一个公共结点ListNode* pFirstCommonNode = pListHeadLong;return pFirstCommonNode;}unsigned int GetListLength(ListNode* pHead){unsigned int nLength = 0;ListNode* pNode = pHead;while(pNode != NULL){++nLength;pNode = pNode->m_Next;}return nLength;}




0 0
原创粉丝点击