【剑指offer】面试题37-两个单链表的第一个公共结点
2017-01-22 20:37
381 查看
问题描述:
输入两个链表,找出链表的第一个公共结点。问题分析:
方法1:粗暴的办法。从一个链表的第一个结点开始,再另一个链表上查找是否是交点(指向结点的指针一样),这样的话,如果一个链表的长度是m,另一个链表的长度是n,则时间复杂度是O(mn)。
方法2:
我们知道链表相交,不仅仅只是结点里的data值一样,next指针也是一样的,也就是说,如果两个链表从某一个结点处开始相交,那么之后两个链表一定是相交的。即就是,链表的相交模型不会是X型,而是Y型。如图。
所以我们可以从后向前找第一个交点,但是这里是单链表,只能从后向前遍历,所以这里采用数据结构stack,将结点的信息存储在栈中,从栈顶开始比较两个结点,如果不一样,则就说明不相交,如果一样,记住当前结点,将两个栈的栈顶元素出栈,继续比较下一个结点,就这样,直到找到不一样的结点,那么上一个结点就是第一个公共结点。但是这种办法需要两个辅助栈,不是最好的办法。
方法3:
求出两个链表的长度,让长的链表先走两个链表长度之差的绝对值步,然后两个链表一起走,直到找到第一个公共结点。这就是所谓的快慢指针法。
方法4:
如果两个单链表相交,将链表的尾和其中任何一个链表的头相接,就会构成一个环,求出环的入口就是连个链表的第一个公共结点;如果链表不相交,就不会构成环。判断链表相不相交的办法,就是直接看他们的最后一个结点是否一样。这种办法之后的文章(判断链表是否带环以及环的入口)会实现,这里暂时不实现。
代码实现(包括测试代码):
#include<iostream> using namespace std; struct ListNode { int _data; ListNode* _pNext; ListNode(int x = 0) :_data(x) ,_pNext(NULL) {} }; ListNode* Create(int arr[],int n) { ListNode* head = new ListNode(arr[0]); ListNode* prev = head; ListNode* cur = prev; for(int i = 1; i < n; ++i) { cur = new ListNode(arr[i]); prev->_pNext = cur; prev = cur; } return head; } size_t GetLength(ListNode* head) { size_t len = 0; ListNode* cur = head; while(cur) { ++len; cur = cur->_pNext; } return len; } ListNode* GetFirstCommonNode(ListNode* head1,ListNode* head2) { size_t len1 = GetLength(head1); size_t len2 = GetLength(head2); ListNode* pLong = head1; ListNode* pShort = head2; int diff = len1 - len2; if(diff < 0)//第一个链表比第二个链表短 { pLong = head2; pShort = head1; diff = len2 - len1; } //让长的链表先走diff步 for(int i = 0; i < diff; ++i) { pLong = pLong->_pNext; } //两个链表一起向后走找第一个交点 while(pLong != NULL && pShort != NULL && pLong != pShort) { pLong = pLong->_pNext; pShort = pShort->_pNext; } if(pLong && pShort == 0)//没有找到公共结点 return NULL; else return pShort; } void Destroy(ListNode* head) { ListNode* cur = head; ListNode* del = NULL; while(cur) { del = cur; cur = cur->_pNext; delete del; } } ListNode* FindNode(ListNode* head,int data) { ListNode* cur = head; while(cur) { if(cur->_data == data) return cur; cur = cur->_pNext; } return NULL; } int main() { int arr1[] = {3,4,5,6,7,8}; int arr2[] = {8,7}; //创建链表 ListNode* head1 = Create(arr1,sizeof(arr1)/sizeof(arr1[0])); ListNode* head2 = Create(arr2,sizeof(arr2)/sizeof(arr2[0])); //创造交点 ListNode* Node1 = FindNode(head1,6); ListNode* Node2 = FindNode(head2,7); Node2->_pNext = Node1; ListNode* ret = GetFirstCommonNode(head1,head2); if(ret) cout<<"交点的值是:"<<ret->_data <<endl; else cout<<"没有交点"<<endl; Destroy(head1); Node2->_pNext = NULL; Destroy(head2); system("pause"); return 0; }
总结:
1、在使长的链表先走diff步的时候,使用pLong来记录长的链表,pShort记录短的链表。如果不这样的话,我们需要判断diff是否大于0,如果是,head1先走diff步,否则head2先走diff绝对值步。所以代码中的处理相当好~~2、销毁两个链表的时候,一定要先将相交的部分进行拆开,如果不这样做的话,第一个链表已经释放的结点,第二个链表释放的时候就会报错。这是测试代码应该注意的地方~
相关文章推荐
- 【剑指offer】面试题37:两个链表的第一个公共结点
- 剑指offer——面试题37:两个链表的第一个公共结点
- 【剑指Offer】面试题37:两个链表的第一个公共结点
- 剑指offer 面试题37 两个链表的第一个公共结点
- 剑指Offer----面试题37:两个链表的第一个公共结点
- 【剑指offer】5.3时间效率与空间效率的平衡——面试题37:两个链表的第一个公共结点
- 剑指offer-面试题37-两个链表的第一个公共结点
- 【剑指offer】面试题37:两个链表的第一个公共结点
- 【剑指offer】面试题37:两个链表的第一个公共结点
- 剑指offer——面试题37:两个链表的第一个公共结点
- 【剑指Offer学习】【面试题37:两个链表的第一个公共结点】
- 剑指offer-面试题37-两个链表的第一个公共结点
- 剑指offer 面试题37 两个链表的第一个公共结点
- 剑指Offer面试题37(Java版):两个链表的第一个公共结点
- 【剑指Offer学习】【面试题37:两个链表的第一个公共结点】
- 剑指offer--面试题37:两个链表的第一个公共结点
- 【面试题】剑指Offer-37-求两个链表的第一个公共节点
- 剑指Offer:两个单链表的第一个公共结点
- 剑指offer-37 两个链表的第一个公共结点
- 剑指offer面试题 求两个链表的第一个公共结点