【算法专题--链表】环形链表--高频面试题(图文详解,小白一看就会!!)

news2024/11/23 12:56:01

目录

一、前言

 二、什么是环形链表?

🥝 环形链表的概念详解

🍇 环形链表的特点 

 🍍环形链表的延申问题

 三、高频面试题

 ✨环形链表

 ✨环形链表II

 ✨环形链表的环长

 四、总结

五、共勉 


一、前言

        环形链表,可以说是--链表专题--,最经典的一种结构,也是在面试中频率最高的一道题目,通常在面试中,面试官可能会根据环形链表的结构延申出很多问题,所以大家需要对这环形链表结构非常熟悉哦!!
      本片博客就来详细的讲讲解一下
环形链表,让我们的面试变的更加顺利!!!

 二、什么是环形链表?

🥝 环形链表的概念详解

       环形链表是一种特殊类型的链表数据结构,其最后一个节点的"下一个"指针指向链表中的某个节点,形成一个闭环。 换句话说,链表的最后一个节点连接到了链表中的某个中间节点,而不是通常情况下连接到空指针 (null) 
       如果大家对链表还不熟悉可以先看看这篇文章:单链表详解

🍇 环形链表的特点 

 特点:
1️⃣:若一个链表带环,那么用指针一直顺着链表遍历,最终会回到某个地方。
2️⃣:  我们可以定义两个指针(快慢指针),两个指针均从表头开始同时遍历链表,快指针一次走两步,慢指针一次走一步。如果链表带环,那么快慢指针一定会相遇,否则快指针会先遍历完链表(遇到NULL)。

  • 若是你不明白为什么链表带环,快慢指针就一定会相遇,那么你可以想想龟兔赛跑: 

 🍍环形链表的延申问题

 1️⃣:为什么慢指针走一步快指针走两步,他们一定会在环里面meet吗?会不会永远追不上?

  •   首先 慢指针快指针一定是快指针先进环
  •  随着慢指针进环快指针已经在环了走了一段距离,走了多少和环的大小有关
  •  假设慢指针进环的时候距离快指针距离为 N快指针开始追慢指针
  •  在追击过程中,快指针往前走两步慢指针往前走一步每走一次它们之间的距离就缩小 1 
  •  它们之间的距离变化为 N ,N-1 ,N-2 , . . . 1 ,0  ,它们之间的距离为 零 就会相遇所以一定追得上

 2️⃣: 为什么一定是 慢指针走一步快指针走两步?快指针能走其它步数吗?

  •  假设慢指针进环的时候,快指针慢指针之间的距离为 N
  •  在追击的时候,快指针走三步慢指针走一步,每走一次,它们之间的距离缩小 2

 此时分两种情况:

  • N 偶数,则它们之间的距离会减少到 0 相遇
  • N奇数,则它们之间的距离会减少到1 然后减少到 -1减少到 -1 也就意味着它们之间的距离又变为 C - 1 (C是环的周长)

此时又分两种情况:

  •  若 C奇数 ,则 C - 1 为偶数 ,因为它们之间的距离一次缩短 2 所以它们会相遇
  •  若 C 偶数 ,则 C - 1 为奇数 ,也就是说它们之间的距离还是奇数,它们永远不会相遇

 由此可以得出结论:快指针一次不走两步,存在追不上的情况。
 所以 必须 ---- 每次慢指针走一步 , 快指针走两步


3️⃣ :如何才能得知 环口 的节点是哪一个呢?

  •  追上的相遇的过程中,慢指针的距离:L+X快指针的距离:L+NC+X
  • 由于不知道 快指针 在环里多跑了几圈,所以设了一个N,但是N肯定>=1, 
  • 因为快指针是满指针的两倍,所以2(L+X)=L+NC+X。整理可得   L= NC - X

     至此,我们发现链表头到环入口的距离 相遇点到环入口的距离 C-X 相差 N 个环的长度。
 
  结论:一个指针指向链表头,一个指针指向第一次相遇点 , 并使两个指针的速度都为 1 ,一直前进直到它们相遇,第二次相遇的位置一定为环的入口位置。

 三、高频面试题

 ✨环形链表

题目链接:141. 环形链表 - 力扣(LeetCode) 

解题思路: 

  • 我们可以使用快慢指针法。定义步长为2的快指针步长为1的慢指针遍历链表。我们假设链表如果存在环,则快慢指针在某一时刻一定会在环内相遇;而如果不存在环,由于快指针速度比慢指针快,因此它们永远无法相遇。

 代码:

class Solution {
public:
    // 题目已经给出了 单链表的 节点构造

    bool hasCycle(ListNode *head) 
    {
        // 定义两个快慢指针
        ListNode* slow = head;    //  每次走一步
        ListNode* fast = head;    //  每次走两步

        // 当链表 有环存在时 fast 和 fast-next 一定不会指向空
        // 当快指针不为空且其下一个节点也不为空时,继续循环
        while(fast!=nullptr && fast->next!=nullptr)
        {
            slow = slow->next;
            fast = fast->next->next;
            // 相交成环
            if(slow == fast)
            {
                return true;
            }
        }
        return false;
    }
};

  疑问:为什么循环的结束条件是fast或者fast->next指向NULL?

  • 当一个链表中有环时,fast和fast->next永远不会指向NULL
  • 当一个链表中没有环时,fast一定会移动到链表的结尾;又因为fast一次移动两个节点,所以有两种情况:①fast移动两次后,刚好指向NULL,结束循环;②fast移动一次后就已经指向NULL,此时再进行移动,就会出现对NULL的解引用

 ✨环形链表II

 题目链接:142. 环形链表 II - 力扣(LeetCode)

解题思路: 

  • 起初快指针速度为2,慢指针速度为1,如果快慢指针没有相遇,则返回NULL代表不存在环;如果相遇了,我们就让 其中一个指针重新指向链表头,并使 两个指针的速度都为1,一直前进直到它们相遇,相遇的位置一定为环的位置。这是因为从 相遇点走 L 步后的位置与走C - X 步后的位置一致。

代码: 

class Solution {
public:
    ListNode *detectCycle(ListNode *head) 
    {
        // 初始化两个指针,快指针fast和慢指针slow,都指向链表头节点
        ListNode* slow = head;
        ListNode* fast = head;


        // 当快指针和其下一位都不为空时(即未到达链表尾部)
        while(fast&&fast->next)
        {
             // 慢指针每次前进一步
             slow = slow->next;
             // 快指针每次前进两步
            fast = fast->next->next;

            // 如果两个指针第一次相遇
            while(slow==fast)
            {
                // 将相遇的节点赋值给 meet变量
                ListNode* meet = fast;

                // 从头节点开始,另一个指针从相遇点开始,两者每次各前进一步
                // 直到两个指针再次相遇,相遇点即为环的起始节点
                while(head!=meet)
                {
                    head = head->next;
                    meet = meet->next;
                }

                // 返回找到环的入口节点
                return meet;
            }
        }

        return NULL;
    }
};

✨环形链表的环长

题目描述: 
给定一个链表的头节点 head ,返回链表环中环的长度。 如果链表无环,则返回 0。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。

解题思路: 

  • 我们同样可以先使用快慢指针判断链表是否存在环,当二者第一次相遇时说明链表存在环。而当快慢指针相遇后我们再次让快慢指针进行追逐战,此时它们之间的距离为环长 C,由于每次追逐它们的距离都会缩短1,因此我们可以定义一个计数器count记录第二次相遇时所追逐的次数即为链表的环长。具体过程如下:

代码: 

 struct ListNode {
    int val;
    struct ListNode* next;
    
};
int CycleLength(struct ListNode* head)
{
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while (fast && fast->next) //当到达或即将到达链表尾时退出循环
    {
        //快慢指针移动
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow) //第一次相遇,存在环
        {
            //统计第二次相遇所追逐的次数
            int count = 0;
            do
            {
                fast = fast->next->next;
                slow = slow->next;
                count++;
            } while (fast != slow);
            //相遇了,返回追逐次数即为环长
            return count;
        }
    }
    //不存在环,返回0
    return 0;
 
}

 四、总结

         以上就是今天要讲的内容,做题的时候,就是奔着双指针的思路进行解决的,练习这么多次现在逐渐找到了点感觉。我感觉就是双指针的关键点就是在于该怎么去移动两个指针,理清这一点之后离结果也就不远了,判断链表是否有环应该是老生常谈的一个话题了,最简单的一种方式就是快慢指针。慢指针针每次走一步,快指针每次走两步,如果相遇就说明有环,如果有一个为空说明没有环。所以就赶紧记录一下这时刻。

五、共勉 

     以下就是我对 环形链表 的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对 链表专题 的理解,请持续关注我哦!!! 

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

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

相关文章

VSCode超过390万下载的请求插件

Thunder Client 是一款在 VSCode(Visual Studio Code)中非常受欢迎的 REST API 客户端插件,由Ranga Vadhineni开发,现在已经有超过390万的下载量。它允许开发者直接在编辑器内发送 HTTP 请求,查看响应。Thunder Client…

力扣hot100:739. 每日温度/54. 螺旋矩阵

文章目录 一、 739. 每日温度二、54. 螺旋矩阵1、模拟螺旋矩阵的路径2、按层模拟 一、 739. 每日温度 LeetCode:739. 每日温度 经典单调栈问题,求下一个更大的数。 使用单调递减栈,一个元素A出栈,当且仅当它第一次出现比它更大…

bitset用法

参考:https://blog.csdn.net/weixin_45697774/article/details/105563993 题目:https://leetcode.cn/problems/maximum-total-reward-using-operations-ii/description/ class Solution { public:int maxTotalReward(vector<int>& rewardValues) {bitset<10000…

46.django - 多语言配置

1.Django 多语言基础知识 多语言站点可以让不同语言的用户更好地使用和理解网站内容&#xff0c;提升用户体验和覆盖范围。为了实现多语言功能&#xff0c;我们将使用Django内置的国际化和本地化支持。我收集了一些知识点整理在这一部分&#xff0c;感兴趣的可以看看。直接跳过…

单臂路由的配置(思科、华为)

#交换设备 不同vlan属于不同广播域&#xff0c;不能互相通信&#xff0c;他们配置的是不同网段的IP地址&#xff0c;针对不同网段的IP地址进行通信&#xff0c;就需要用到路由技术 实现不同vlan之间的通信技术有两种 单臂路由三层交换 单臂路由 一、思科设备的单臂路由配…

【python】OpenCV—Histogram Matching(9.2)

学习来自OpenCV基础&#xff08;17&#xff09;基于OpenCV、scikit-image和Python的直方图匹配 文章目录 直方图匹配介绍scikit-image 中的直方图匹配小试牛刀风格迁移 直方图匹配介绍 直方图匹配&#xff08;Histogram Matching&#xff09;是一种图像处理技术&#xff0c;旨…

Web 自动化测试(基于Pytest极简)

Pytest 初体验 在使用 Python 进行 Web UI 自动化测试时&#xff0c;我们除了使用 unittest 单元测试框架&#xff0c;还可以使用 pytest&#xff0c;本节实验就给大家简单的介绍一下 pytest。 环境配置 本系列实验我们借助 VS Code 工具编写代码&#xff0c;使用的 Python …

[Llama3] ReAct Prompt 测试实验

ReAct 是一种 LLM 提示和结果处理方法&#xff0c;结合了推理、行动计划和知识源整合&#xff0c;使 LLM 超越其语言模型&#xff0c;并在预测中使用来自现实世界的信息。 ReAct 是推理和行动的结合。 介绍 ReAct 的论文表明它比思维链提示更好。与后者不同的是&#xff0c;Re…

【数据结构(邓俊辉)学习笔记】图06——最小支撑树

文章目录 0. 概述1. 支撑树2. 最小支撑树3. 歧义性4. 蛮力算法5. Prim算法5.1 割与极短跨越边5.2 贪心迭代5.3 实例5.4 实现5.5 复杂度 0. 概述 学习下最小支撑树和prim算法。 1. 支撑树 最小的连通图是树。 连通图G的某一无环连通子图T若覆盖G中所有的顶点&#xff0c;则称…

Layui弹框中设置输入框自动获取焦点无效/Layui设置Input框自动获取焦点无效,怎么办?

1、问题概述? 有时候为了用户体验,期望当弹框打开的时候,指定的输入框能自动的获取焦点,用户就可以直接输入了。提升了用户体验。但有时候设置的时候没有效果。 2、正常的设置自动获取焦点方式 【input框设置方式】 使用关键字autofocus <input type="text&quo…

Linux - 逻辑卷的创建和管理

1.逻辑卷LVM的创建 1.1 创建步骤 ①添加硬盘或者创建分区 ②创建物理卷 pvcreate ③创建卷组 vgcreate ④创建逻辑卷 lvcreate ⑤创建文件系统 mkfs.xfs/ect4/... ⑥创建挂…

安装搭建java版的悟空crm遇到 网络错误请稍候再试 终极解决办法(hrm人力资源模块)

java版 项目目录 ├── build – webpack 配置文件 ├── config – 项目配置文件 ├── src – 源码目录 │ ├── api – axios请求接口 │ ├── assets – 静态图片资源文件 │ ├── components – 通用组件 │ ├── directives – 通用指令 │ ├── filters –…

状态方程ABCD矩阵如何确定例子

状态方程ABCD矩阵如何确定 确定状态空间表示中的状态矩阵A、输入矩阵 B、输出矩阵C 和直通矩阵D,需要从系统的动力学方程出发,并将其转换为状态方程的形式。我们可以通过一个具体的物理系统(如倒立摆系统)来说明这一过程 例子:倒立摆系统 系统描述 考虑一个倒立摆系统…

串口RS232 RS485

RS232 RS232是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是“数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准”。 该标准规定采用一个25个脚的DB-25连接器&#xff…

Cocos2dx 编译游戏安装包制作教程

在本教程中&#xff0c;我们将学习如何为 Visual Studio 编译项目配置图标&#xff0c;并使用 Inno Setup 创建安装包。我们将包括以下部分&#xff1a; 设置项目图标&#xff1a;在 Visual Studio 中配置 .exe 文件的图标&#xff0c;或者使用第三方工具替换编译后的图标。创…

王学岗鸿蒙开发(北向)——————(七、八)ArkUi的各种装饰器

arts包含如下&#xff1a;1&#xff0c;装饰器 &#xff1b;2&#xff0c;组件的描述(build函数)&#xff1b;3&#xff0c;自定义组件(Component修饰的),是可复用的单元&#xff1b;4&#xff0c;系统的组件(鸿蒙官方提供)&#xff1b;等 装饰器的作用:装饰类、变量、方法、结…

汇编语言LDS指令

在8086架构的实模式下&#xff0c;LDS指令&#xff08;Load Pointer Using DS&#xff09;用于从内存中加载一个32位的指针到指定寄存器和DS寄存器。我们来详细解释一下这条指令为什么会修改DS段寄存器。 LDS指令的功能 LDS指令格式如下&#xff1a; LDS destination, sourc…

SNAT与DNAT

一、SNAT策略概述 1、SNAT 策略的典型应用环境 局域网主机共享单个公网IP地址接入Internet&#xff08;私有IP不能在Internet中正常路由&#xff09; 局域共享上网 2、 SNAT 策略的原理 修改数据包的源地址 把从内网 --> 外网的数据的源内网地址转换成公网源地址 3、SN…

多目标检测模型加权框集成

优秀项目推荐&#xff1a;https://gitcode.com/ZFTurbo/Weighted-Boxes-Fusion/overview 参考链接&#xff1a; 目标检测加权框融合 WBF原理讲解 https://blog.csdn.net/YXD0514/article/details/132574588 目标检测加权框融合 WBF原理讲解&#xff08;Weighted Boxes Fusion&…

java中集合List,Set,Queue,Map

Java SE中的集合框架是一组用于存储和操作对象的类和接口。它提供了丰富的数据结构&#xff0c;可以用于解决各种问题。Java SE中的集合框架包含以下主要类和接口&#xff1a; 一. Collection接口&#xff1a; 是集合框架的根接口&#xff0c;它定义了一些通用的集合操作方法…