两个链表的第一个公共节点(剑指offer)
来源:互联网 发布:c语言改文件名 编辑:程序博客网 时间:2024/05/21 09:23
题目:输入两个链表,找出它们的第一个公共节点.链表节点定义如下:
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; }
本题我们后面并没有浪费额外的空间:需要我们务必注意的是(以空间换时间并不一定都是可行的方案.我们要注意需要的辅助空间的大小,消耗太多的内存可能得不偿失.如果是关于嵌入式方面的,那么对于空间的消耗就要格外留心,因为通常嵌入式系统的内存很有限,,,,)
- 剑指offer-两个链表的第一个公共节点
- 【剑指offer】两个链表的第一个公共节点
- 剑指offer-两个链表的第一个公共节点
- 【剑指offer】两个链表的第一个公共节点
- 剑指offer------两个链表的第一个公共节点
- 《剑指offer》两个链表的第一个公共节点
- 剑指offer-两个链表的第一个公共节点
- 剑指offer--两个链表的第一个公共节点
- 剑指offer 两个链表的第一个公共节点
- 【刷题剑指offer】两个链表的第一个公共节点
- 剑指offer(38):两个链表的第一个公共节点
- 两个链表的第一个公共节点(剑指offer)
- 剑指offer面试题37 两个链表的第一个公共节点
- [剑指offer][面试题37]两个链表的第一个公共节点
- 剑指offer 面试题37—两个链表的第一个公共节点
- 剑指offer之两个链表的第一个公共节点
- 剑指offer 37 - 两个链表的第一个公共节点
- 《剑指Offer》面试题:寻找两个链表的第一个公共节点
- eclipse实用操作
- 已有表格排序
- 关于一些些框架的技术
- 均值局部磨皮
- springmvc中线程池(ThreadPoolTaskExecutor)的配置
- 两个链表的第一个公共节点(剑指offer)
- 蓝豹特效
- 做长图片
- 重要时间点提醒工具软件
- 导出数据进excel
- scala之正则表达式(二)内部匹配函数
- C#对List中的数据进行取交集、并集、差集和去重操作的方法
- 12306 API 研究
- 数据结构——Stack