1、题目描述
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表:
示例1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
2、VS2019上运行
使用哈希表来实现
#include<iostream>
using namespace std;
#include<unordered_set>
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode *> visited; // 用于存储已经访问过的节点
ListNode *temp = headA; // 用一个临时指针指向链表A的头节点
while (temp != nullptr) { // 遍历链表A
visited.insert(temp); // 将当前节点加入到已访问节点集合中
temp = temp->next; // 移动到下一个节点
}
temp = headB; // 将临时指针指向链表B的头节点
while (temp != nullptr) { // 遍历链表B
if (visited.count(temp)) { // 如果当前节点在已访问节点集合中出现过,说明是交点。出现就是1
return temp; // 返回交点节点
}
temp = temp->next; // 移动到下一个节点
}
return nullptr; // 如果没有交点,则返回nullptr
}
};
int main() {
// Create example lists
ListNode* a1 = new ListNode(4);
ListNode* a2 = new ListNode(1);
ListNode* a3 = new ListNode(8);
ListNode* a4 = new ListNode(4);
ListNode* a5 = new ListNode(5);
ListNode* b1 = new ListNode(5);
ListNode* b2 = new ListNode(0);
ListNode* b3 = new ListNode(1);
ListNode* b4 = new ListNode(8);
ListNode* b5 = new ListNode(4);
ListNode* b6 = new ListNode(5);
// Generate intersection by connecting nodes
a1->next = a2;
a2->next = a3;
a3->next = a4;
a4->next = a5;
b1->next = b2;
b2->next = b3;
b3->next = b4;
b4->next = b5;
b5->next = b6;
// Connect the intersection node
a5->next = b4;
Solution obj;
ListNode* intersectionNode = obj.getIntersectionNode(a1, b1);
if (intersectionNode != nullptr) {
cout << "Reference of the node with value= " << intersectionNode->val << endl;
}
else {
cout << "No intersection point found." << endl;
}
// Clean up memory
delete a1;
delete a2;
delete a3;
delete a4;
delete a5;
delete b1;
delete b2;
delete b3;
delete b4;
delete b5;
delete b6;
return 0;
}
运行结果为:
Reference of the node with value= 8
3、哈希表(Hash table)的使用
在C++中,哈希表(Hash Table)通常使用以下两种方式实现:
std::unordered_map 和 std::unordered_set:这些是C++标准库提供的两个容器,它们分别实现了无序映射(unordered map)和无序集合(unordered set)。它们使用哈希表作为底层数据结构,并提供了插入、删除和查找操作,以及哈希函数和键的相等性比较函数。
1、insert():插入函数
2、count():用于查找给定键或元素在容器中出现的次数的成员函数。它适用于 std::unordered_map、std::unordered_set、std::map、std::set 等容器类型
对于 std::unordered_map 和 std::unordered_set,count() 返回一个整数值,表示给定的键或元素在容器中出现的次数。如果键或元素存在,则返回1,如果不存在,则返回0
4、两种方法
(1)方法一:双指针法
- 大部分人,包括官方题解也是这么做的
- 两个链表长度分别为L1+C、L2+C, C为公共部分的长度,按照楼主的做法: 第一个人走了L1+C步后,回到第二个人起点走L2步;第2个人走了L2+C步后,回到第一个人起点走L1步。 当两个人走的步数都为L1+L2+C时就相遇了
class Solution {
public:
ListNode* FindFirstCommonNode(ListNode* headA, ListNode* headB) {
ListNode* node1 = headA; // 初始化指针node1指向链表A的头节点
ListNode* node2 = headB; // 初始化指针node2指向链表B的头节点
while (node1 != node2) { // 当node1和node2不相等时,继续循环
node1 = node1 != nullptr ? node1->next : headB; // 如果node1不为空,将node1移动到下一个节点;如果node1为空,则将node1移动到链表B的头节点
node2 = node2 != nullptr ? node2->next : headA; // 如果node2不为空,将node2移动到下一个节点;如果node2为空,则将node2移动到链表A的头节点
}
return node1; // 返回node1,即为两个链表的第一个公共节点,如果不存在公共节点则返回nullptr
}
};
(2)方法二:哈希表法
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode *> visited; // 用于存储已经访问过的节点
ListNode *temp = headA; // 用一个临时指针指向链表A的头节点
while (temp != nullptr) { // 遍历链表A
visited.insert(temp); // 将当前节点加入到已访问节点集合中
temp = temp->next; // 移动到下一个节点
}
temp = headB; // 将临时指针指向链表B的头节点
while (temp != nullptr) { // 遍历链表B
if (visited.count(temp)) { // 如果当前节点在已访问节点集合中出现过,说明是交点。出现就是1
return temp; // 返回交点节点
}
temp = temp->next; // 移动到下一个节点
}
return nullptr; // 如果没有交点,则返回nullptr
}
};