数据结构练级之路【判断两条链表是否有交点】题目讲解

简介: 数据结构练级之路【判断两条链表是否有交点】题目讲解

一、题目:

1.(相交链表)(只能聚合,不能发散,Y字形,不是X字形)

给你两个单链表的头结点headA,headB,请你找出并返回相交单链表的起始结点,如果两个链表没有交点就返回NULL;


思路一:(暴力求解法)遍历A链表,依次取A链表中的每一个结点,依次跟B链表中的的所有结点比较,如果有地址相同的结点,就是相交,第一个相同的交点(前提是要让我的链表的长度保持一致)

思路二:优化从O(N^2)到 O(N)

1.尾结点相同就是相交,否则就是不想交(因为如果这个链表是一个有交点的链表,那么它的尾结点就一定是相交的,因为链表只能是Y 字形的结构,不是X字形的结构)

所以此时直接找尾,然后判一下就行了

2.求交点:此时就是想让这个代码是时间复杂度为O(2*N),就是双指针一起向后走(然后同一个位置的结点进行比较,如果相同就表示有交点)

但是这种原理的前提是两个链表要是相同的长度的,所以这变我们此时就要把链表的长度先给求出来(然后让更长的那个链表先走x步,走到最后跟较短的那个链表的长度一样,然后开始比较)

3.头结点就是头结点,不能乱给它移动位置,所以都是用一个cur去迭代找尾


1.故事理解代码:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    //你是一个农村出身的穷小伙,她是一个一线城市的富家女,你爱上了她,你们的故事就此开始...
    //如果你们两没有遇见对方,此生无缘
    if (!headA || !headB)
        return NULL;
    int lengthA = 0;
    int lengthB = 0;
    struct ListNode *pA = headA;
    struct ListNode *pB = headB;
    //这是你目前的实力
    while(pA->next != NULL){
        pA = pA->next;
        lengthA++;
    }
    //这是她目前的实力
    while(pB->next != NULL){
        pB = pB->next;
        lengthB++;
    }
    //富家女的父亲和你谈话,摆明了你和她目前的差距是天与地,好让你认清现实,放弃他女儿
    int mid = lengthA - lengthB;
    struct ListNode *ppA = headA;
    struct ListNode *ppB = headB;
    //但是你不肯放手,想要与命运搏一搏,所以日以继夜的充实自己,追赶者她的步伐
    while (mid > 0){
        ppA = ppA->next;
        mid--;
    }
    while (mid < 0){
        ppB = ppB->next;
        mid++;
    }
    //你不断努力,终于把你和她之间的差距缩小到了最小
    //然后你们领了证,开始了婚后的平淡生活
    while( ppA != ppB){ //结局1 : 结婚后,诸多因素导致了你与她产生了嫌隙,最终,你们不欢而散
        ppA = ppA->next;
        ppB = ppB->next;
    }
    return ppA; //结局2 : 一直到最后你们仍旧和以前一样相濡以沫,走完了这一生,恭喜!
}

2.理论理解代码:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    //这个题目的重点就是如何理解交点:要明白交点就是在同一位置时相等的点叫交点,不是相等就是交点,一定要是同一个位置才算是交点,所以假如链表长度不同,怎么可能在多余的地方找到交点
    struct ListNode *tailA=headA;
    struct ListNode *tailB=headB;
    //此时有了这两个尾指针我就要开始找尾了(然后进行尾的比较,如果尾的位置都不相同,那么就肯定不相交,因为根据图或者原理,可以知道只要这个是一个相交的链表那么尾肯定是相交的)
    //并且此时为了可以方便后面的计算,我们这边可以顺便把链表的长度给计算一下
    int lenA=1;
    while(tailA)
    {
        lenA++;
        tailA=tailA->next;
    }
    int lenB=1;
     while(tailB)
    {
        lenB++;
        tailB=tailB->next;
    }
    if(tailA!=tailB)
    {
        return NULL;
    }
    int gab=abs(lenA-lenB);//这个位置也可以使用三目操作符
     struct ListNode*longlist=headA;
      struct ListNode*shortlist=headB;
      if(lenA<lenB)
      {
          longlist=headB;
          shortlist=headA;
      }
    while(gab)//就是为了让我的末尾的位置对齐,才可以进行比较
    {
        longlist=longlist->next;
        gab--;
    }
    //此时程序来到这个位置就是说明我的链表是一样长的了
    while(longlist!=shortlist)
    {
        longlist=longlist->next;
        shortlist=shortlist->next;
    }
  //程序来到这个位置,自然而然的是说明我此时地址的位置相等,自然就是找到了相交的位置了
    return longlist;
}


相关文章
|
8月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
204 30
|
8月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
322 25
|
9月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
359 5
|
10月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
11月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
889 9
|
11月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
229 59
|
4月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
61 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
9月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
338 77
|
8月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
171 11