《算法之美》の链表问题の两链表相交问题

Xterminal、Termius、MobaXterm怎么选?2026跨平台SSH工具实测对比 命令行与远程服务器管理是运维和开发日常最高频的操作之一,而SSH客户端则是连接云端与本地最关键的桥梁。无论是排查Linux服务器异常、配置密钥登录,还是通过跳板机访问内网资源,选择一款顺手且稳定的终端工具能显著提升工作效率。当前主流跨平台工具中,Xterminal以原生中文和AI辅助见长,Termius在移动端与多设备同步上表现突出,MobaXterm则以功能全能的Windows集成工具箱著称。本文从实际工程场景出发,围绕中文支持、SSH密钥管理、跳板机配置、连接保活和SFTP文件传输等高频需求,对三款工具 阅读详情

编程判断两个链表是否相交

问题:给出两个单向链表的头指针,比如head1和head2,判断这两个链表是否相交。这里给出简化问题,假设两个链表均不带环。

 

解答:首先了解一下这个问题的工程实践,例如在一个大的系统中,如果出现两个链表相交的情况,一旦程序释放了其中的一个链表的所有节点,那样就会造成第二个链表信息的丢失。因此,我们需要在释放一个链表之前知道是否有其他链表与当前链表相交。

 

直观的想法:

判断第一个链表的每一个节点是否在第二个链表中,这需要O(Length(head1)*Length(head2))的时间复杂度,需要改进;

 

利用计数的方法:

如果两个链表相交,那么这两个链表存在共同的节点。而节点地址是节点的唯一标识。因此,我们只需判断两个链表中是否存在地址一致的节点即可。一个简单的方法是对第一个链表的节点地址进行哈希排序,建立哈希表,然后针对第二个链表的每个节点的地址查询哈希表,如果它在哈希表中出现说明两个链表相交。这个方法的时间复杂度是O(Length(head1)+Length(head2)),但是它同时需要附加O(Length(head1))的存储空间,以存放哈希表。

 

对问题进行转化:

由于两个链表没有环,我们可以将第二个链表接在第一个链表后面,如果得到的链表有环,说明这两个链表相交。否则,这两个链表不相交。因此,这就把问题转化为判断链表是否有环了。

如果这个新链表有环,那么第二个链表的表头一定在环上,我们从第二个链表开始遍历,看是否会回到起始点就可以判断出来了。最后我们还得记住将链表恢复原状,去掉第一个链表指向第二个链表表头的指针。

这个算法的时间复杂度是线性的,且只需要常数的空间。

 

问题的最终解决方案:

抓住本质:如果两个没有环的链表相交于某一点,那么在这个节点之后的所有节点都是这两个链表所共有的。如果两个链表相交,那么最后一个节点一定是共有的,因此,先遍历第一个链表,记住最后一个节点;再遍历第二个链表,到最后一个节点时和第一个链表的最后节点比较,如果相同,则相交,否则不相交。

这个算法时间复杂度是O(Length(head1)+Length(head2)),且仅用了一个额外的指针来存放第一个链表的最后一个节点。

 

完整代码如下:

#include <iostream>

#include <assert.h>

 

struct ListNode

{

    int m_nKey;

    ListNode* m_pNext;      

};

 

void InitList(ListNode** head)

{

    *head = (ListNode*)malloc(sizeof(ListNode));

    (*head)->m_pNext = NULL;    

}

 

void InsertList(ListNode* head, int data)

{

   assert(head != NULL);

   ListNode* pNewNode = (ListNode*)malloc(sizeof(ListNode));

   pNewNode->m_nKey = data;

   pNewNode->m_pNext = head->m_pNext;

   head->m_pNext = pNewNode;     

}

 

bool IsListIntercource(ListNode* head1, ListNode* head2)

{

    if(head1 == NULL || head2 == NULL)

        return false;

    ListNode* pNode = head1;

    while(pNode->m_pNext != NULL)

    {

        if(pNode->m_pNext->m_pNext == NULL)

        {

            pNode = pNode->m_pNext;                         

            break;

        }

        pNode = pNode->m_pNext;                       

    }    

   

         if((head2->m_pNext == NULL) && (pNode == head2))

        return true;

 

    while(head2->m_pNext != NULL)

    {

        if(head2->m_pNext->m_pNext == NULL)

        {

            if(pNode == head2->m_pNext)

                return true;

            else

                return false;                          

        }                  

                   head2 = head2->m_pNext;

    }

}

 

 

int main()

{

    ListNode* pListHead1 = NULL;

    ListNode* pListHead2 = NULL;

    InitList(&pListHead1);

    InitList(&pListHead2);

   

    //建立两个链表

    for(int i=9; i>=0; i--)

    {

        InsertList(pListHead1, i);

        InsertList(pListHead2, i);          

    }

    //新建一个节点

    ListNode* pListNode = (ListNode*)malloc(sizeof(ListNode));

    pListNode->m_nKey = 100;

    pListNode->m_pNext = NULL;

   

    

    ListNode* pTemp = pListHead1;

    while(pTemp->m_pNext != NULL)

    {

        pTemp = pTemp->m_pNext;                         

    }

    pTemp->m_pNext = pListNode; //将新节点接在链表后面

   

    pTemp = pListHead2;

    while(pTemp->m_pNext != NULL)

    {

        pTemp = pTemp->m_pNext;                       

    }

    pTemp->m_pNext = pListNode; //将新节点接在链表后面

   

    //判断两个链表是否相交

    if(IsListIntercource(pListHead1, pListHead2))

    {

        std::cout<<"两个链表相交"<<std::endl;

    }

    else

    {

        std::cout<<"两个链表不相交"<<std::endl;   

    }

   

    system("pause");

    return 0;

}

 

=======================================================

扩展问题:两个单向链表,编程找出它们的第一个公共节点

 

解答:在上一题中已经提到,如果两个链表有一个公共节点,那么该公共节点之后的所有节点都是重合的,那么,它们的最后一个节点必然也是重合的。因此,判断两个链表是否有重复部分,只要分别遍历两个链表的最后一个节点。如果两个尾节点是一样的,那么两个链表重合,否则两个链表没有公共的节点。

顺着上面的思路,顺序变量两个链表到尾节点时,我们并不能保证在两个链表上同时到达尾节点。这是因为两个链表长度不一定一样。如果假设链表1比链表2多x个节点,我们可以先在链表1上遍历前x个节点,之后再和链表2同步遍历,这样就可以保证同时到达最后一个节点了。由于两个链表从第一个公共节点开始到链表的尾节点部分都是重合的,因此,它们肯定也同时到达第一个公共节点。在遍历中,第一个相同的节点就是第一个公共的节点。

最后我们的方案是:先分别变量两个链表得到它们的长度,并求出两个长度之差x。在长链表上先遍历x次之后,再同步变量第二个链表,直到找到相同的节点或一直到链表结束。

该算法的时间复杂度是O(Length(head1)+Length(head2))。

 

完整代码如下:

#include <iostream>

#include <assert.h>

 

struct ListNode

{

    int m_nKey;

    ListNode* m_pNext;      

};

 

void InitList(ListNode** head)

{

    *head = (ListNode*)malloc(sizeof(ListNode));

    (*head)->m_pNext = NULL;    

}

 

void InsertList(ListNode* head, int data)

{

   assert(head != NULL);

   ListNode* pNewNode = (ListNode*)malloc(sizeof(ListNode));

   pNewNode->m_nKey = data;

   pNewNode->m_pNext = head->m_pNext;

   head->m_pNext = pNewNode;     

}

 

bool IsListIntercource(ListNode* pHead1, ListNode* pHead2)

{

    if(pHead1 == NULL || pHead2 == NULL)

        return false;

    ListNode* pNode = pHead1;

    while(pNode->m_pNext != NULL)

    {

        if(pNode->m_pNext->m_pNext == NULL)

        {

            pNode = pNode->m_pNext;                         

            break;

        }

        pNode = pNode->m_pNext;                       

    }    

   

         if((pHead2->m_pNext == NULL) && (pNode == pHead2))

        return true;

 

    while(pHead2->m_pNext != NULL)

    {

        if(pHead2->m_pNext->m_pNext == NULL)

        {

            if(pNode == pHead2->m_pNext)

                return true;

            else

                return false;                          

        }                  

                   pHead2 = pHead2->m_pNext;

    }

}

 

int ListLength(ListNode* pHead)

{

    int nLength = 0;

    ListNode* pNode = pHead;

    while(pNode->m_pNext != NULL)

    {

        ++nLength;

        pNode = pNode->m_pNext;                    

    }   

    return nLength;

}

 

//核心算法,获得第一个相交的节点

ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2)

{

    ListNode* pListHeadLong = NULL;

    ListNode* pListHeadShort = NULL;

    int nLen1 = ListLength(pHead1);

    int nLen2 = ListLength(pHead2);

    int nDiff = nLen1 - nLen2;

    if(nDiff >= 0)

    {

        pListHeadLong = pHead1;

        pListHeadShort = pHead2;

    } 

    else

    {

        pListHeadLong = pHead2;

        pListHeadShort = pHead1;

        nDiff = -(nDiff);   

    }

   

    //长链表先遍历nDiff个节点

    for(int i=0; i<nDiff; i++)

        pListHeadLong = pListHeadLong->m_pNext;

   

    //接着在两个链表上同时遍历

    while((pListHeadLong != NULL) &&

           (pListHeadShort != NULL) &&

           (pListHeadLong != pListHeadShort))

    {

        pListHeadLong = pListHeadLong->m_pNext;

        pListHeadShort = pListHeadShort->m_pNext;      

    }

   

    //返回第一个相交的节点

    ListNode* pFirstCommonNode = NULL;

    if(pListHeadLong == pListHeadShort)

        pFirstCommonNode = pListHeadLong;

   

    return pFirstCommonNode;

}

 

 

int main()

{

    ListNode* pListHead1 = NULL;

    ListNode* pListHead2 = NULL;

    InitList(&pListHead1);

    InitList(&pListHead2);

   

    //建立两个链表

    for(int i=9; i>=0; i--)

    {

        InsertList(pListHead1, i);

        InsertList(pListHead2, i);          

    }

   

    //新建一个节点

    ListNode* pListNode = (ListNode*)malloc(sizeof(ListNode));

    pListNode->m_nKey = 200;

    pListNode->m_pNext = NULL;

   

    

    ListNode* pTemp = pListHead1;

    while(pTemp->m_pNext != NULL)

    {

        pTemp = pTemp->m_pNext;                         

    }

    pTemp->m_pNext = pListNode; //将新节点接在链表后面

   

    pTemp = pListHead2;

    while(pTemp->m_pNext != NULL)

    {

        pTemp = pTemp->m_pNext;                       

    }

    pTemp->m_pNext = pListNode; //将新节点接在链表后面

   

    ListNode* pCommon =  FindFirstCommonNode(pListHead1, pListHead2);

    std::cout<<"第一个相交的节点值是:"<<pCommon->m_nKey<<std::endl;

   

    system("pause");

    return 0;

}

 

 

副露のMagic的弱智算法学习 day4 今日主要内容:链表基础(两两交换链表中的节点、删除链表的倒数第N个节点、面试题 02.07. 链表相交、环形链表II、总结)1、简单复习昨天使用的双指针法based on C++ 学习依据代码随想录:)给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。示例 1: 输入:head = [1,2,3,4] 输出:[2,1,4,3] 愚蠢的尝试(该部分都是杂乱想法,不一定正确) 使用三个指针(也许是所谓的双指针法) 阅读详情

相关推荐

优化求解器性能:当分支切割算法中的gap停滞不前时如何应对

本文深入探讨了当分支切割算法求解复杂整数规划问题时,gap停滞不前的根本原因与应对策略。文章指出gap停滞源于上界(找不到更优整数解)或下界(证明过程缓慢)提升受阻,并提供了从模型改写、自定义割平面、调整搜索策略到参数调优等一系列实战方法,帮助优化工程师有效打破求解僵局,推动gap下降。

weixin_29294597的博客 381

链表面试题之链表相交问题

如果你放弃那便没有人可以救得了你了,反而如果你坚持下去或许会有不一样的收获

微风 3688

国民技术N32G45X SysTick定时器实战:从1us到100ms的精准延迟实现(附完整代码)

本文详细解析了国民技术N32G45X芯片中SysTick定时器的工作原理,并提供了从1微秒到100毫秒的高精度延迟实现方案。通过对比官方库函数的局限性,文章重点介绍了无中断查询模式、时钟源选择策略以及完整的代码实现,帮助嵌入式开发者精准控制时序,适用于LED控制、软件模拟通信协议等多种实战场景。

weixin_29190573的博客 374

leetcode.面试题 02.07. 链表相交

面试题 02.07. 链表相交 给定两个(单向)链表,判定它们是否相交并返回交点。请注意相交的定义基于节点的引用,而不是基于节点的值。换句话说,如果一个链表的第k个节点与另一个链表的第j个节点是同一节点(引用完全相同),则这两个链表相交。 示例 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

eilot_c的博客 303

【SAP】ABAP——ALV显示后选择数据操作

在ALV显示后,可全选、全不选或者选择几条数据进行发邮件、更新、下单等等操作。 在user_command中的实现方式如下: 方式一: FORM user_command USING ucomm LIKE sy-ucomm selfield TYPE slis_selfield. DATA: lr_grid TYPE REF TO cl_gui_alv_grid. DATA: lt_rows TYPE lvc_t_row WITH

Mona_1220的博客 4091

通达信股本变迁文件(gbbq)解密方法

近年来A股市场跌宕起伏真特么精彩,本人愚钝,被整爆仓,损失惨重 痛定思痛,认为交易这种对纪律要求极高,且必须完全排除情绪影响的勾当,还是应该交给程序来干 数据哪里来呢?当然是拿来主义。。。问券商的交易软件要呗 到处查资料,得知通达信的权息文件数据齐全,不仅含有除权除息数据,还含有限售解禁、增发、可转债上市等股本变化数据 ——这对于某些对成交量变化敏感的交易模型是非常重要的

不甘碌碌老,结庐铸宝刀 2万+

代码随想录一一一链表一一一链表相交

君の名字

Dustw1nd的技术小屋 196

告别混乱!在Unity中为Best MQTT v3设计清晰的服务层:配置、连接、订阅发布模块拆分指南

本文详细介绍了如何在Unity中使用Best MQTT v3插件构建清晰的服务层架构,包括配置管理、连接服务、订阅管理和发布服务的模块化拆分。通过解耦设计、事件驱动和接口抽象,提升代码可维护性和可测试性,适用于物联网和实时通信开发场景。

weixin_30576827的博客 357

常见の算法链表问题

【代码】常见の算法链表问题。

yiyeyeshenlan的博客 443

四足机器人关节电机控制器实现(附C++代码)

本文先对做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容。

qq_35635374的博客 461

131、高通骁龙影像平台总览:Spectra ISP 各代架构演进与特性对比

摘要:本文深入分析了高通骁龙Spectra ISP从250到780代的架构演进与技术痛点,揭示了各代关键改进与隐藏问题。重点剖析了双ISP带宽分配、AI ISP黑盒决策、温度控制等实战问题,并给出具体解决方案(如寄存器配置、QoS调整等)。文章强调工程师需平衡带宽、功耗与画质的三角关系,建议调试时先关闭AI模块建立基线,关注统计引擎配置,并建立温度监控机制。最后指出理解架构局限比追求完美设计更重要,需要针对不同场景找到合适的妥协方案。(148字)

sundong_81的博客 207

月のLeetCode 每周刷题之 Week3

142. 环形链表 II 给定一个链表,返回链表开始入环的第一个节点。如果链表无环,则返回null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 不允许修改 链表。 class Solution { public: ListNode *...

sukiki09的博客 845

基于深度学习的道路裂缝检测系统完整教程

本文介绍了一种基于深度学习的道路裂缝检测系统完整解决方案。项目采用5466张高质量道路裂缝图像数据集,包含YOLO和Pascal VOC两种标注格式,覆盖多种道路场景。系统利用CNN和YOLO算法实现高效检测,相比传统人工巡检显著提升效率和准确性。文中详细阐述了数据集结构、环境配置和训练流程,包括数据预处理、智能分割策略和质量检查方法。该技术可及时发现道路裂缝隐患,降低维护成本,保障交通安全,为道路养护提供智能化解决方案。

FJN110的博客 297

《动态规划》之--字符串比较问题(扩展距离)

问题:对于长度相同的2个字符串A和B,其距离定义为相应位置字符距离之和。2个非空格字符的距离是它们的ASCII码之差的绝对值;空格与空格的距离为0,空格与其他字符的距离为一个定值k。在一般情况下,字符串A和B的长度不一定相同。字符串A的扩展是在A中插入若干空格字符所产生的字符串。在字符串A和B的所有长度相同的扩展中,有一对距离最短的扩展,该距离称为字符串A和B的扩展距离。对于给定的字符串A和B

ASCE1885 1万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

音乐随机播放算法

常见的音乐随机播放算法主要有两种:一是Shuffle算法;二是Random算法。 一 Shuffle算法 Shuffle算法和排序算法正好相反,是从有序到乱序的一个过程,俗称洗牌算法。它将播放列表中的歌曲顺序打乱,变成一个和原来歌曲顺序没有任何关系的乱序的播放列表,之后进行歌曲的播放,并支持当用户点击“上一首”时,能够回到刚刚播放的那一首歌曲。 二 Random算法 Random算法是

ASCE1885 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

《算法之美》---进程互斥软件算法(Lamport面包店算法和Eisenberg算法)

实现进程互斥的软件的结构框架是:Framework         Repeat                   entry section                   critical section                   exit section                   remainder section         Until false进程互斥的软件实现算法有:Lamport面包店算法和Eisenberg算法。这两种算法均假定系统中进程的个数有限,如n个。1

ASCE1885 8133

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

桶排序及其应用

桶排序(Bucket Sort)有时也称为盒子排序(Bin Sort),来源于邮局使用的盒子信件分发方法。桶排序的有效性需假定输入数据是由一个完全随机过程产生,即要求桶排序的输入数据呈均匀分布,例如,输入数据随机均匀分布在区间[0, 1)。 桶排序思想如下: 1)把区间[0, 1)分解为n个大小相等的桶; 2)将n个输入数据按照其取值不同分配到n个桶里面; 3)对每个桶里面的数

ASCE1885 5639

《算法之美》の链表问题の从链表中删除节点

问题:假设一个没有头指针的单链表。一个指针指向此单链表中间的一个节点(既不是第一个,也不是最后一个节点),请将该节点从单链表中删除。链表结点定义如下:struct ListNode{         int       m_nKey;         ListNode* m_pNext;};解答:假设给定的指针为pCurrent,ListNode* pNext = pCurrent->m_pNext;由题意知,pCurrent指向链表的某一个中间节点,因此pCurrent->m_pNext != NULL。

ASCE1885 4169

线段树的代码模板

线段树的应用:1)求面积:一.坐标离散化;二.垂直边按x坐标排序;三.从左往右用线段树处理垂直边,累计每个离散x区间长度和线段树长度的乘积。2)求周长:一.坐标离散化;二.垂直边按x坐标排序,第二关键字为入边优于出边;三.从左往右用线段树处理垂直边,在每个离散点上先加入所有入边,累计线段树长度变化值,再删除所有出边,累计线段树长度变化值;四.水平边按y坐标排序,

ASCE1885 3617

《算法之美》---次序选择问题

当一个序列排好序之后,我们一般会对其有两种操作:一是对其进行查找操作;一是得知任何特定元素在一个序列中的次序。当如果我们仅仅想知道某一个或某几个元素在序列里的次序,或者处于某个特定位置上的元素,则并不一定需要对整个序列进行排序。 在一个序列里面挑选处于特定位置的元素的问题就是所谓次序选择问题。一般定义如下:在n个元素里面选择出第i小(或大)的元素,即找出排名为i的元素。 快速次序选择算法是比直

ASCE1885 2931

线段树

树结构的基本思想是分割。普通二叉搜索树是按对象来进行划分,效果往往和数据结构内对象有关;而线段树是根据关键码的可能范围来分的,这种技术叫做关键空间分解! 线段树的处理对象是线段(一般意义上的区间可以抽象成线段),它把线段组织成利于检索和统计的形式,本质上是线段的二叉搜索树!当然,线段树特殊点在与其中的线段可以分解和合并,另外,线段树操作的是整个区间,它的渐进时间效率不依赖于数据结构中的对象

ASCE1885 2678

《算法之美》の链表问题の获得链表中倒数第m个元素

问题: 给定一个单向链表,设计一个时间优化并且空间优化的算法,找出该链表的倒数第m个元素。实现您的算法,注意处理相关的出错情况。m定义为当m=0时,返回链表最后一个元素。   解答: 这是一个难题,因为单向链表只能正向遍历,这个问题需要根据元素与链表尾的相对位置来找出该元素,但是当发现链表尾时,没有简单的办法回溯到倒数第m个元素。   我们需要的是倒数第m个元素

ASCE1885 2676

《算法之美》---二叉堆及其实现

<br />二叉堆是一棵满足下列性质的完全二叉树:<br />1)如果某节点有孩子,则根节点的值都小于孩子节点的值。我们称之为小根堆;<br />2)如果某节点有孩子,则根节点的值都大于孩子节点的值。我们称之为大根堆。<br />这样,如果我们用一维数组a存储来存储该堆,那么具有n个节点的堆可看成是一棵按层次排列,同一层按自左向右排列的完全二叉树。显然,小根堆的根节点是最小值,大根堆的根节点是最大值,计算过程分下面两步进行:<br />(1)—建堆,把数组a中各个元素转变成堆;<br />(2)—对数组a进

ASCE1885 2591

Parliament--POJ--1032

ParliamentTime Limit: 1000MSMemory Limit: 10000KTotal Submissions: 10936Accepted: 4570DescriptionNew convocation of The Fool Lands Parliament consi

ASCE1885 2369
上一篇: 《算法之美》の链表问题の从链表中删除节点
下一篇: 《算法之美》の链表问题の单向链表的反转
ACE1985
博客等级 码龄17年 1307粉丝 308原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值