findFirstCommonNode
来源:互联网 发布:排列组合c的快速算法 编辑:程序博客网 时间:2024/05/18 22:46
findFirstCommonNode
输入两个链表,找出它们的第一个公共结点。
[牛客 url]https://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?tpId=13&tqId=11189&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
- 解法一(书上解法)
找出2个链表的长度,然后让长的先走两个链表的长度差,然后再一起走(因为2个链表用公共的尾部)
时间复杂度O(m+n)
/*struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { }};*/class Solution {public: ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { ListNode *p1=pHead1; ListNode *p2=pHead2; int len1=0,len2=0,diff=0; // 求长度 while(p1!=NULL){ p1=p1->next; len1++; } while(p2!=NULL){ p2=p2->next; len2++; } // 求步数差,并且把p1置为长的List头结点 if(len1>len2){ diff=len1-len2; p1=pHead1; p2=pHead2; } else{ diff=len2-len1; p1=pHead2; p2=pHead1; } // 追赶指针技巧 for(int i=0;i<diff;i++){ p1=p1->next; } while(p1!=NULL && p2!=NULL){ if(p1==p2) break; p1=p1->next; p2=p2->next; } return p1; }};
解法二(leetcode 神解法):用两个指针扫描”两个链表“,最终两个指针到达 null 或者到达公共结点。
解释:
假定 List1长度: a+n List2 长度:b+n, 且 a<b
那么 p1 会先到链表尾部, 这时p2 走到 a+n位置,将p1换成List2头部
接着p2 再走b+n-(n+a) =b-a 步到链表尾部,这时p1也走到List2的b-a位置,还差a步就到可能的第一个公共节点。
将p2 换成 List1头部,p2走a步也到可能的第一个公共节点。如果恰好p1==p2,那么p1就是第一个公共节点。
或者p1和p2一起走n步到达列表尾部,二者没有公共节点,退出循环。 同理a>=b.
class Solution {public: ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { ListNode *p1 = pHead1; ListNode *p2 = pHead2; while(p1 != p2){ p1 = (p1 == NULL? pHead2: p1->next); p2 = (p2 == NULL? pHead1: p2->next); } return p1; }};
讨论上其他解法:
设表1长度n,表2长度m,暴力法嵌套遍历两个链表需要O(mn)的时间复杂度,
可以采用hash的思想将其中一个转存为哈希表结构,这样建哈希表时间O(m),
而遍历链表时间O(n),而遍历时查找哈希表的时间为O(1),因此复杂度降为O(m+n),
但需要辅助空间。(这种哈希优化的策略是种一般性的思路,谨记!)
链接:https://www.nowcoder.com/questionTerminal/6ab1d9a29e88450685099d45c9e31e46
class Solution {public: ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { if(pHead1==NULL||pHead2==NULL)return NULL; unordered_multiset<ListNode*> hashset; ListNode *pNode1=pHead1,*pNode2=pHead2; //把链表2转存为哈希表 while(pNode2!=NULL){ hashset.insert(pNode2); pNode2=pNode2->next; } //遍历第一个链表 while(pNode1!=NULL){ if(hashset.find(pNode1)!=hashset.end()){ return pNode1; } pNode1=pNode1->next; } return NULL; }};
更新:重新想一下,当链表有环的时候,上述应该是不完全对的;
先判断两个链表是否有环,如果两个都没有环,才是上述走法;
如果一个有环一个没环,肯定不相交;
如果两个都有环,先判断一个链表上的终点是否在另一个链表上。 // 暂时没想到,待更
- findFirstCommonNode
- 新手C#代码简洁性—函数篇
- 自定义控件
- 【基础Back to base】数据结构相关Tips(1)
- 新手C#代码简洁性—语义篇
- java定时器(TaskTimer)Spring配置及范例
- findFirstCommonNode
- ERP报表网格分组思路
- 数组、ArrayList、List<T>区别和选择
- Maven中POM.XML详解(1)
- Uncaught SyntaxError: Unexpected token o in JSON at position 1
- ASP.NET分析器错误消息: 未能加载类型的问题“ComradeSoft.Base.Admin.Login”?
- iOS11以及iPhone X遇到的相关问题
- 三 调试 Progressive Web Apps
- nginx+tomcat 配置负载均衡