剑指offer 学习笔记 两个链表的第一个公共节点

面试题52:两个链表的第一个公共节点。输入两个链表,找出它们的第一个公共节点,链表节点定义如下:

struct ListNode {
    int m_nKey;
    ListNode* m_pNext;
};

蛮力法:在第一个链表上顺序遍历每个节点,每遍历到一个节点,就在第二个链表上顺序遍历每个节点,直到找到第一个公共节点,如果第一个链表长为m,第二个链表长度为n,那么时间复杂度为O(mn),太慢了。

法二:我们可以把两个链表分别放到两个栈中,而栈顶元素一定是一样的,因为最后一个元素一定是公共的节点,接着从两个栈中出栈一个元素,再比较栈顶元素,直到两个栈顶元素不同,那么上次出栈的节点即为第一个公共节点。这种方法的时间复杂度为O(m+n),空间复杂度也是O(m+n),与蛮力法相比,时间效率得到了提高,但是以牺牲空间效率为代价。

法三:法二牺牲了空间效率换来了时间性能的提升,也可以先遍历两个链表,从而得到长度,即得到了两链表的长度差,之后长的先遍历长度差个节点,之后两个链表再一起向尾部遍历,直到找到第一个相同的节点。这种方法时间复杂度也是O(m+n),但不需要辅助栈。

以下代码使用下图链表为例:
在这里插入图片描述

#include <iostream>
using namespace std;

struct ListNode {
    int m_nKey;
    ListNode* m_pNext;
};

int GetListLength(ListNode* head) {
    ListNode* pNode = head;
    int count = 0;
    while (pNode != nullptr) {
        ++count;
        pNode = pNode->m_pNext;
    }
    return count;
}

ListNode* FindFirstCommonNode(ListNode* head1, ListNode* head2) {
    if (head1 == nullptr || head2 == nullptr) {
        return nullptr;
    }

    int length1 = GetListLength(head1);
    int length2 = GetListLength(head2);

    ListNode* longList = head1;
    ListNode* shortList = head2;
    int lengthDif = length1 - length2;

    if (length1 < length2) {
        longList = head2;
        shortList = head1;
        lengthDif = -lengthDif;
    }

    while (lengthDif > 0) {
        longList = longList->m_pNext;
        --lengthDif;
    }

    while (longList != nullptr) {
        if (longList == shortList) {
            break;
        }
        longList = longList->m_pNext;
        shortList = shortList->m_pNext;
    }
    return longList;
}

int main() {
    ListNode* pNode1 = new ListNode();
    ListNode* pNode2 = new ListNode();
    ListNode* pNode3 = new ListNode();
    ListNode* pNode4 = new ListNode();
    ListNode* pNode5 = new ListNode();
    ListNode* pNode6 = new ListNode();
    ListNode* pNode7 = new ListNode();

    pNode1->m_nKey = 1;
    pNode2->m_nKey = 2;
    pNode3->m_nKey = 3;
    pNode4->m_nKey = 4;
    pNode5->m_nKey = 5;
    pNode6->m_nKey = 6;
    pNode7->m_nKey = 7;

    pNode1->m_pNext = pNode2;
    pNode2->m_pNext = pNode3;
    pNode3->m_pNext = pNode6;
    pNode4->m_pNext = pNode5;
    pNode5->m_pNext = pNode6;
    pNode6->m_pNext = pNode7;
    pNode7->m_pNext = nullptr;

    ListNode* commonNode = FindFirstCommonNode(pNode1, pNode4);
    if (commonNode) {
        cout << "第一个公共节点值为:" << commonNode->m_nKey << endl;
    } else {
        cout << "没有公共节点。" << endl;
    }
}
posted @   epiphanyy  阅读(5)  评论(0编辑  收藏  举报  
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示