剑指Offer52.两个链表的第一个公共节点 C++

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
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值