前言
这道题用到的思想和前几道题一样,涉及到了双指针这种,整体难度不大。
题目
描述
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
数据范围:
n
≤
1000
n≤1000
n≤1000
要求:空间复杂度
O
(
1
)
O(1)
O(1),时间复杂度
O
(
n
)
O(n)
O(n)
例如,输入
1
,
2
,
3
,
4
,
5
,
6
,
7
{1,2,3},{4,5},{6,7}
1,2,3,4,5,6,7时,两个无环的单向链表的结构如下图所示:
可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。
输入描述:
输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。
返回值描述:
返回传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表。
解决方案一
1.1 思路阐述
这个思路一是不满足题目要求的空间复杂度 O ( 1 ) O(1) O(1),空间复杂度为 O ( n ) O(n) O(n),但是也是AC了的。
这个思路是受BM6的启发。
因为找第一个公共节点,所以其实我们要找的是节点的地址而非节点的值。因为节点在内存中的地址是唯一的,我们只要判断节点地址是否出现同样的即可(这个就类似于判断有没有环)。所以我们使用STL的set容器可以很好的做到这一点。
代码里面首先是将一条链表的所有节点放到容器中去,接着在容器中查找 p H e a d 2 pHead2 pHead2的每一个节点。如果找不到,那么 f i n d find find函数会自动返回set容器的最后一个索引位置,所以这里我判断使用的是 m y S e t . e n d ( ) mySet.end() mySet.end()。找不到则将节点加入到set中去,继续遍历下一个节点。
找不到则返回空指针,找到了则表示这个节点就是公共节点。
1.2 源码
#include <iterator>
#include <vector>
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
std::set<ListNode *> mySet;
while (pHead1) {
mySet.insert(pHead1);
pHead1=pHead1->next;
}
for (auto it=mySet.begin(); it!=mySet.end();it++) {
if(!pHead2)
break;
if(mySet.find(pHead2)==mySet.end())
{
mySet.insert(pHead2);
pHead2=pHead2->next;
}
else {
return pHead2;
}
}
return nullptr;
}
};
解决方案二
2.1 思路阐述
采用双指针法。
这个有点类似于找最小公倍数。
算法流程如下:
使用两个指针分别从两个链表头节点出发
两个指针分别走完当前链表后,再从另一个链表重新开始走,直到相遇
当他们走的步数刚好相等时,两个指针第一次相遇
举个例子,一个链表A长度为5,一个链表B长度为4。它们对应的指针a和b都从链表表头开始按序遍历节点。
假设两个链表存在公共节点,也就是说两个链表指针都会遍历同一个节点。因为是一次遍历一个节点,不是跳着遍历,所以两个链表最终肯定会碰到一起,因为算法中将指针的遍历做了一个循环操作,也就是把单向链表变成了循环链表来遍历。那两个不等长的链表什么时候链表指针走过的节点数会实现等长, 5 ∗ 4 = 20 5*4=20 5∗4=20,也就是说,两个指针走20个节点开始,接下来的节点应该是同样的节点,这不刚好就是第一个公共节点吗。
2.2 源码
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
int len1 = get_ListLength(pHead1);
int len2 = get_ListLength(pHead2);
ListNode *p1 = pHead1, *p2 = pHead2;
if(len1 > len2){
while(len1 > len2){
p1 = p1->next;
--len1;
}
}
if(len2 > len1){
while(len2 > len1){
p2 = p2->next;
--len2;
}
}
while(p1){
if(p1 == p2) return p1;
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
int get_ListLength(ListNode* head){
int len = 0;
while(head){
head = head->next;
++len;
}
return len;
}
};
总结
链表题常用算法,双指针。两个链表之间的关系比较,考虑STL容器。