【链表面试题】解决环形链表和相交链表问题

news2024/11/16 3:40:52

在力扣上发现这样的几道题,尝试做了一下,也发现了一个关于这类题的一种做法:快慢指针的使用。废话不多说,上例题

目录

一、环形链表

1.定义(概念)

2.如何判断是否为环形链表

1.快慢指针

2.为什么快指针一次走两个结点

3.例题分析

二、相交链表

1.例题分析

2.解法分析

总结


一、环形链表

1.定义(概念)

所谓的环形链表,无非是这一种,如图所示

 这样的链表,就可以称为环形链表。

2.如何判断是否为环形链表

给定一链表,我们怎么判断是否为环形链表呢?

接下来我们认识一下快慢指针的概念

1.快慢指针

快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减肥。

就是以表头为初始位置,我们定义fast、slow两个结点,指向head头节点,fast每一次,走两个结点,slow每一次走一个结点,如果有环,必然会相遇(fast==slow),注意哦,是指针地址相等哦!如果无环的话,就会fast更快的走到链表末尾,指向NULL

2.为什么快指针一次走两个结点

假设链表带环,两个指针最后都会进入环里面,快指针先进入环,慢指针后进入环、当慢指针刚计入环的时候,可能就和快指针相遇了,最差的情况是相距环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况(无法相遇),因此,在慢指针走到一圈之前,快指针肯定能追上慢指针的,即相遇!

如图所示:

 如图所示:

3.例题分析

力扣icon-default.png?t=N0U7https://leetcode.cn/problems/linked-list-cycle/这是例题链接,环形链表

题目如下:

AC代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode *fast=head;
    struct ListNode *slow=head;
 
    // if(fast!=NULL||fast->next!=NULL){
    //     return false;
    // }
    while(fast!=NULL&&fast->next!=NULL){
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow){
            return true;
        }
    }
    return false;
}

1.while循环,因为head为头节点,head为NULL,说明为空链表,head->next为NULL,说明只有一个结点,无法构成环。

2.我们使用while循环,使用快慢指针,fast步长为2,slow步长为1,如果fast==slow返回为true(有环),循环结束之后,返回false(无环)

还有一种比较暴力的解法:

代码如下:

    while(head!=NULL){
        if(head->val==100000){
            return true;
        }
        head->val=100000;
        head=head->next;
    }
    return false;

第二个可以用快慢指针的题目

链表中倒数第k个结点_牛客题霸_牛客网

如图:

我们使用快慢指针的思路是,fast如果与slow同时移动的话,移动一次,fast与slow指向的指针差距都会加一,所以,倒数第k给结点,只需要,fast与slow距离为k的时候,两者再以都以步长为1移动,fast,移动到NULL时,slow指向的就是倒数第k个节点

代码如下:

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

/**
 * 
 * @param pListHead ListNode类 
 * @param k int整型 
 * @return ListNode类
 */
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    // // write code here
    // if(pListHead==NULL){
    //     return NULL; //判断是否为NULL
    // }
    // struct ListNode*cur=pListHead;
    // int count=0;
    // while(cur!=NULL){
    //     count++;
    //     cur=cur->next;
    // }
    // //得到了结点个数
    // if(count==0){
    //     return NULL;  //如果空链表,自然返回NULL
    // }
    // int num=count+1-k;//这是num得到倒数第k个结点  count-k+1
    // if(k>count||k<=0){    //如果k大于count,当然是不行的,小于0也不行,都返回NULL
    //     return NULL;
    // }
    // while(--num){     //然后进行循环即可
    //     pListHead=pListHead->next;
    // }
    // return pListHead;

//快慢指针问题,设计两个指针,fast和slow两种,然后先移动fast指针k步,然后一起移动两个指针,直到fast移动到NULL的时候,slow就是倒数第k个结点
    struct ListNode*fast=pListHead;
    struct ListNode*slow=pListHead;
    while(k--){
        if(fast==NULL){
            return NULL;//如果为空链表,那么就返回NULL
        }
        fast=fast->next;
    }
    while(fast){
        fast=fast->next;
        slow=slow->next;
    }
    return slow;
}

while循环移动k次,然后同时步长为1移动,直到fast为NULL,这就是使用快慢指针的思路。

当然被//的是普通的做法,一并附上

二、相交链表

如图:

1.例题分析

力扣https://leetcode.cn/problems/intersection-of-two-linked-lists/

2.解法分析

第一种如图所示:

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL||headB==NULL){
        return NULL;
    }
   struct ListNode*p=headA;
   struct ListNode*q=headB;
    while(p!=q){
        p=p==NULL?headB:p->next;
        q=q==NULL?headA:q->next;//因为比较的是指针的地址,所以如果指向NULL之后,还可以继续找到头节点
        //1.结点数相同的时候,一次遍历就能得到是否有相交,这个结点就是p指向的位置,如果没有,p正好指向null
        //2.如果结点数不同的时候,那么因为不同,所以当结点数小的那个遍历一边的时候,结点数大的还没完成,这样永远差一个结点数之差的位置,然后继续接上上两个头节点,这样第二轮,就是在尾部对齐的情况下,起始位置相同,这样一轮必然能得到答案
    }
    return p;
}

第二种解法分析:

主要是,先遍历得到两条链表的长度,pq分别指向链表头节点headA、headB然后将长的那个链表的头节点给p结点,然后得到两链表结点个数之差,num=lenA-lenB,然后将p结点移动num次,while循环,然后再同时移动p和q结点,进行判断是否有相交结点

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL||headB==NULL){
        return NULL;
    }
//    struct ListNode*p=headA;
//    struct ListNode*q=headB;
//     while(p!=q){
//         p=p==NULL?headB:p->next;
//         q=q==NULL?headA:q->next;//因为比较的是指针的地址,所以如果指向NULL之后,还可以继续找到头节点
//         //1.结点数相同的时候,一次遍历就能得到是否有相交,这个结点就是p指向的位置,如果没有,p正好指向null
//         //2.如果结点数不同的时候,那么因为不同,所以当结点数小的那个遍历一边的时候,结点数大的还没完成,这样永远差一个结点数之差的位置,然后继续接上上两个头节点,这样第二轮,就是在尾部对齐的情况下,起始位置相同,这样一轮必然能得到答案
//     }
//     return p;

//第二种做法
//目的是,我们想让他们尾部对齐,然后在同长度的情况下,遍历,这样就能找到相交结点,或者NULL
    struct ListNode*p=headA;
    struct ListNode*q=headB;
    if(headA==NULL||headB==NULL){
        return NULL;
    }
    //取得第一个A链表的长度
    int lenA=0;
    while(p!=NULL){
        lenA++;
        p=p->next;
    }
    int lenB=0;
    while(q!=NULL){
        lenB++;
        q=q->next;
    }

    //找到之后,将最大的结点数都给A  就是交换位置
    p=headA;
    q=headB;
    if(lenA<lenB){
        //交换结点长度
        int temp=lenA;
        lenA=lenB;
        lenB=temp;
        //交换链表头节点
        struct ListNode*node=p;
        p=q;
        q=node;
    }
    //这样得到的是A为最长结点
    //两个结点相互减去
    int count=lenA-lenB;
    while(count--){
        p=p->next;       
    }
    while(p!=q){
        p=p->next;
        q=q->next;
    }
    return p;
}

总结

了解了快慢指针这一概念,对于环形链表会进行判断了,相交链表的问题,也可以实现了,不过值得一提的是,力扣讨论区里面,真的不少好玩有趣的解法。

比如经典的 return true; (50%答案)真的好逗!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/195976.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

限期出国|CSC资助赴世界top50名校英国曼彻斯特大学访学

我们先为J老师40天获得佐治亚理工学院&#xff08;美国三大理工学院之一&#xff09;的访问学者邀请函&#xff0c;又成功申报CSC。后因其担心被美国拒签要求重新申请英国名校&#xff0c;10天后拿到跻身世界top50英国曼彻斯特大学的offer&#xff0c;后经ATAS审批、CSC改派、使…

linux基本功系列-help命令实战

文章目录前言&#x1f680;&#x1f680;&#x1f680;一. help命令介绍二. 语法格式及常用选项三. 参考案例3.1 显示某个命令的帮助信息3.2 查看某个命令的简述3.3 以伪man手册格式输出cd信息四. windows中的help总结前言&#x1f680;&#x1f680;&#x1f680; 想要学好Lin…

车载网络 - Autosar网络管理 - 基本概念

Autosar作为当前车载行业使用最为广泛的一种汽车开发系统架构&#xff0c;网上也有很多相关的介绍&#xff1b;不过我看很多有完整的来讲一下这个规范的&#xff0c;一般都是只讲了其中一部分&#xff0c;我这就准备搞出来一套完整版本的Autosar网络管理的规范、测试设计、自动…

新C++(7):多态那些事儿_下

"当人类悬浮到腐朽&#xff0c;有谁愿追随彗星漂流哦~"一、多态原理(1)虚函数表指针(虚表指针)紧接上一篇sizeof(Base)这一小段说起。class Base1 { public:void func(){} private:int _a; };class Base2 { public:virtual void func() {} private:int _a; };我们知道…

【我刚毕业,学习Java开发工程师能学会吗?没有基础?】

对于Java专业来说&#xff0c;学历还是有一定的要求。一般都是本科学历&#xff0c;至少也有个大专&#xff0c;其次就是年龄越年轻越好。现在转行Java的年轻人很多&#xff0c;学历这方面越高越有竞争力一些&#xff0c;尤其是在后期的职业晋升阶段。如果想走管理路线&#xf…

耗时一周整体,这4款黑科技电脑软件,功能强大到离谱

闲话少说&#xff0c;直上狠货。 1、有道云笔记 有道云这是一款国民级的文稿编辑器&#xff0c;俗话说得好&#xff0c;好记性不如烂笔头&#xff0c;强大实用的笔记软件&#xff0c;能让你的工作与学习事半功倍。5大文稿类型&#xff0c;让记录得心应手&#xff0c;随时进行创…

第十四章 集合(Set)

一、Set 接口&#xff08;P518&#xff09; 1. Set接口基本介绍 &#xff08;1&#xff09;无序&#xff08;添加和取出的顺序不一致&#xff09;&#xff0c;没有索引 &#xff08;2&#xff09;不允许重复元素&#xff0c;所以最多包含一个 null 2. Set接口的常用方法 和 …

SpringBoot中MQ使用

本文记录学习在Spring Boot中使用MQ。一 什么是MQMQ全称&#xff08;Message Queue&#xff09;又名消息队列&#xff0c;是一种异步通讯的中间件。它的作用类似于邮局&#xff0c;发信人(生产者)只需要将信(消息)交给邮局&#xff0c;然后由邮局再将信(消息)发送给具体的接收者…

博途1200PLC/1500PLCMODBUS从站通信应用

博途PLC作为MODBUS主站通信请参看下面的文章链接: 博途PLC 1200/1500PLC MODBUS-RTU通讯优化(状态机编程)_博途plc modbus-rtu通信优化_RXXW_Dor的博客-CSDN博客博途PLC 1200/1500PLC MODBUS-RTU通讯_RXXW_Dor的博客-CSDN博客_博图modbus通讯1、1200PLC的modbus通讯,可以参看…

HTTP协议(1)

1)HTTP协议是倾向于相遇业务层次上面的一种协议&#xff0c;传输层协议主要考虑的是端对端之间的一个传输过程&#xff0c;TCP重点进行关注的是可靠传输&#xff1b;咱们的HTTP/1&#xff0c;HTTP/2是基于TCP的&#xff0c;但是咱们的HTTP/3是基于UDP的&#xff0c;但是当下的互…

实战动态代理

代理模式介绍代理模式有点像老大和小弟&#xff0c;也有点像分销商。主要解决的是问题是为某些资源的访问、对象的类的易用操作上提供方便使用的代理服务。而这种设计思想的模式经常会出现在我们的系统中&#xff0c;或者你用到过的组件中&#xff0c;它们都提供给你一种非常简…

【CVPR 2018】PU-Net: Point Cloud Upsampling Network

文章目录PU-Net: Point Cloud Upsampling Network网络架构训练数据生成点特征嵌入Feature ExpansionCfoordinate Reconstruction端到端训练Joint Loss FunctionPU-Net: Point Cloud Upsampling Network 网络架构 PU-Net有四个组件&#xff1a;patch extraction, point feature…

「自定义类型」C语言中的构造数据类型如结构,联合,枚举

​​​​​​​&#x1f680;&#x1f680;&#x1f680;大家觉不错的话&#xff0c;就恳求大家点点关注&#xff0c;点点小爱心&#xff0c;指点指点&#x1f680;&#x1f680;&#x1f680;目录 &#x1f430;结构 &#x1f3e1; 前言 &#x1f338;数据类型的定义 &…

SpringBoot动态导出word文档(完美实整教程 复制即可使用,不能实现你找我)

背景 最近有一个需求是需要动态导出合同、订单等信息&#xff0c;导出一个word文档供客户进行下载查看。 需要导出的word文件&#xff0c;主要可以分为两种类型。 导出固定内容和图片的word文档导出表格内容不固定的word文档 经过对比工具&#xff0c;我实践过两种实现方式…

一文细说引导内存分配器

一、引导内存分配器 1.引导内存分配器的作用 因为内核里面有很多内存结构体&#xff0c;不可能在静态编译阶段就静态初始化所有的这些内存结构体。另外&#xff0c;在系统启动过程中&#xff0c;系统启动后的物理内存分配器本身也需要初始化&#xff0c;如伙伴分配器&#xff…

OD笔试题-空汽水瓶可以换汽水

/*** 某商店规定&#xff1a;三个空汽水瓶可以换一瓶汽水&#xff0c;允许向老板借空汽水瓶&#xff08;但是必须要归还&#xff09;。* 小张手上有n个空汽水瓶&#xff0c;她想知道自己最多可以喝到多少瓶汽水。* 数据范围&#xff1a;输入的正整数满足 1≤n≤100* <p>*…

springboot 多环境配置yml

创建多个配置文件 创建文件时注意&#xff0c;一定是 application-文件名称.yml 这种格式 application.yml #主配置文件 application-dev.yml #开发环境的配置 application-prod.yml #生产环境的配置application-prod.yml # 生产环境端口为90 server:port: 90applica…

Python实现将一段话txt生成字幕srt文件

Python实现将一段话txt生成字幕srt文件 作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 一、为什么要将txt转换成字幕 1.1方便到剪辑软件剪辑 有时获取到一段文本&#xff0c;想要直…

点分治学习笔记

有时候我们会碰到一些树上的路径问题&#xff0c;如果需要处理的规模很大的话&#xff0c;这时候点分治是一个很好的工具&#xff0c;往往可以在O(nlogn)的复杂度内完成操作&#xff0c;一般用于离线处理问题 前置芝士 树的重心&#xff1a;最大子树的值最小的点叫做重心。 …

【手撕面试题】HTML+CSS(高频知识点二)

目录 面试官&#xff1a;页面导入样式时&#xff0c;使用 link 和 import 有什么区别&#xff1f; 面试官&#xff1a;简要说说 title与h1的区别、b与strong的区别、i与em的区别&#xff1f; 面试官&#xff1a;img标签的title和alt有什么区别&#xff1f; 面试官&#xff…