您的位置:首页 > 其它

两个链表的第一个公共节点(剑指offer)

2016-08-03 13:52 302 查看
题目:输入两个链表,找出它们的第一个公共节点.链表节点定义如下:

struct ListNode
{
int m_key;
ListNode* m_pNext;
}
面试的时候,碰到这道题,我们的第一反应蛮力法:在第一个链表上顺序遍历每个节点,每遍历到一个节点的时候,在第二个链表上顺序遍历每个节点,每遍历到一个节点的时候,在第二个链表上顺序遍历每个节点,如果在第二个链表上有一个节点和第一个链表上的节点一样,说明两个链表在这个节点上重合,于是就找到了它们的第一个公共节点.如果第一个链表的长度为m,第二个链表的长度为n,显然该方法的时间复杂度为O(mn).
通常蛮力法都不是好办法,一定还有更好的办法.

好了,继续题中的思路进行分析吧!!!

1,我们接下来试着分析有公共节点的两个链表有那些特点.从链表节点的定义可以看出,这两个链表是单向链表.

  如果两个单向链表有公共的节点,那么这两个链表从某一节点开始,它们的m_pNext都指向同一个节点.但由于

  是单向链表的节点,每个节点都只有一个m_pNext,因此从第一个节点开始,之后它们所有的节点都是重合的,

  不可能出现分叉.所以两个公共节点而部分重合的链表,拓扑形状看起来像一个Y,而不可能是X,如下:

  


  分析之后,我们发现:如果两个链表有公共节点,那么公共节点出现在两个链表的尾部.如果我们从两个链表的

  尾部开始往前进行比较的话,最后一个相同的节点就是我们要找的节点.但是,但是,

  问题是:在单向链表中,我们只能从头节点开始按顺序遍历,最后才能到达尾节点.最后到达的尾节点却要被先

  比较,这听起来好像"后进先出"????

  于是,我们就能想到用栈的特点来解决这个问题:分别把两个节点放入栈里,这样两个链表的尾节点就位于这两  个栈的栈顶,接下来比较两个栈的栈顶节点是不算相同.如果相同:则把栈顶弹出接着比较下一个栈顶,直到找  到最后一个相同的节点.

  在上述的思路中,我们需要用两个辅助栈.如果链表的长度分别为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 *pHeadLong = pHead1;
ListNode *pHeadShort = pHead2;
if(nLength2 > nLength1 )
{
ListNode *pHeadLong = pHead2;
ListNode *pHeadShort = pHead1;

nLengthDif = nLength2 - nLength1;

}
//先在长链表上走几步,再同时在两个链表上遍历。
for(int i = 0;i < nLengthDif;i++)
pHeadLong = pHeadLong->m_pNext;

while((pHeadLong != NULL)&&(pHeadShort != NULL)
&&(pHeadLong != pHeadShort ))
{

pHeadLong = pHeadLong->m_pNext;
pHeadShort = pHeadShort->m_pNext;

}
//得到第一个公共节点

ListNode *pFirstCommonNode =    pHeadLong ;

return pFirstCommonNode;

}
//求链表长度的函数
unsigned int GetListLength(ListNode *pHead)
{
unsigned int Length = 0;
ListNode *pNode = pHead;

while(pNode != NULL)
{

++Length;
pNode = pNode->m_pNext;

}

return Length;

}


本题我们后面并没有浪费额外的空间:需要我们务必注意的是(以空间换时间并不一定都是可行的方案.我们要注意需要的辅助空间的大小,消耗太多的内存可能得不偿失.如果是关于嵌入式方面的,那么对于空间的消耗就要格外留心,因为通常嵌入式系统的内存很有限,,,,)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: