《程序员面试金典(第6版)》面试题 02.08. 环路检测(哈希法,双指针,检测链表是否有环)

news2024/11/29 12:54:16

题目描述

给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。若环不存在,请返回 null。
题目传送门:面试题 02.08. 环路检测

  • 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

示例 1:

在这里插入图片描述

 输入:head = [3,2,0,-4], pos = 1
 输出:tail connects to node index 1
 解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

在这里插入图片描述

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

在这里插入图片描述

输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。

进阶:

  • 你是否可以不用额外空间解决此题?

解题思路与代码

  • 这道题算是比较简单的一道题。检测链表是否存在环的最简单的一种方法是哈希法,其次就是快慢指针法。那么前者的空间复杂度可能会高些,但是代码结构简单易懂。

  • 后者虽然说比前者稍微难点,但也没有难太多,多了一点点的思考量而已。

总的来说,这道题是一道好题,考验了你一点点的数学思维,与链表的实际操作

方案一:哈希法

这道题如果是单单的判断链表是否成环,那这道题就是一道简单题,如果还要让你去返回成环的开头节点,那这道题的难度就要上升了。

对于这道题,如果我们用了哈希法,那就是降维打击,因为我们利用unordered_set就可以直接帮你返回相同节点。
具体的代码如下:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode*> set;
        while(head){
            if(set.count(head)) return head;
            set.insert(head);
            head = head->next;
        }
        return nullptr;
    }
};

在这里插入图片描述

复杂度分析:

  • 时间复杂度:O(n),其中n是链表节点的个数
  • 空间复杂度:O(n),我们需要将链表的每一个节点放入集合中,所以是O(n)

方案二: 快慢指针法

  • 先解释一下这里的快慢指针法是什么意思。在这里,我们先设置两个指针,p1,p2。 p1一次走一格,p2一次走两个。因为他们走的步数不一样,所以,如果链表中有环存在了话,那么p1,p2一定不会相等。反之,如果有环,那p1,p2一定会相等。

那这道题的难点在成环节点,在距离头节点多少位置呢?首先,我们要画图分析。
在这里插入图片描述

  • 我们设从头节点,到成环节点的距离为a,成环节点到p2追到p1的距离为b,被追到的p1节点距离再次回到成环节点的距离为c。

  • p2指针一次走两格,p1指针一次走一格,p2追上p1的时候,p2走过的距离是p1的两倍。

  • p1被追到时p2走了a + n(b + c) + b,p1走了a + b所以不难得出这个等式:a + n(b + c) + b = 2(a + b)

  • 将这个等式变化一下便是 **a = c + (n-1)(b+c)**么。

看着这个图,我们来翻译一个这个数学等式的意思。

  • 假设从头节点走了a步,到达了成环节点。便等于我在相遇节点走了 c 步 + n圈。
  • 我们在p1节点与p2节点相遇的时候,再去设置一个p3节点让它等于头节点。这个时候,p3也一次走一步。
  • 你看图,当p3在头节点走了a步的时候,是不是正好与p1在b的时候走了c步 + n圈呢?

具体代码如下:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* p1 = head;
        ListNode* p2 = head;
        while(p2){
            p1 = p1->next;
            if(p2->next)
                p2 = p2->next->next;
            else return nullptr;
            if(p1 == p2) {
                ListNode* p3 = head;
                while(p3!=p1){
                    p1 = p1->next;
                    p3 = p3->next;
                }
                return p3;
            }
        }
        return nullptr;
    }
};

在这里插入图片描述

复杂度分析:

  • 时间复杂度:O(N),N为节点的长度。因为你在实际推演的过程中会发现,p1指针走过的最长的路程也不会超过链表中节点的个数,而是等于节点的个数,所以时间复杂度是O(N)
  • 空间复杂度:O(1),我们设置了几个变量而已,没有使用额外的数据结构,所以是O(1)。

总结

这道题目是一个经典的链表问题,经常出现在计算机科学和软件工程的面试和教程中。

这道题目的主要意义和重要性可以从以下几个方面来看:

  • 数据结构理解与应用:这道题目需要你理解和操作链表这种基础数据结构。理解数据结构的特性和操作方法是编程和算法学习的基础。

  • 双指针技巧:这道题目需要使用到双指针(快慢指针)的技巧。这是一个常用的算法设计策略,可以帮助解决一些看似复杂的问题。

  • 算法分析:通过这道题目,你需要理解和分析算法的时间复杂度和空间复杂度。这道题的解决方案有一个很好的性质:它只需要常量的额外空间,且时间复杂度为线性。

  • 问题解决和调试能力:这道题目也可以帮助你提升问题解决和调试的能力。理解为什么这个解决方案能够工作,对于提升你的算法设计和问题解决能力是非常有帮助的。

所以,这道题目的意义不仅仅是解决一个具体的问题,更重要的是通过这个问题来学习和提升你的数据结构知识,算法设计和问题解决能力。

最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容

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

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

相关文章

操作系统第一章练习题

目录 问答题 选择题 填空题 判断题 问答题 1、设计现代OS的主要目标是什么&#xff1f; 答&#xff1a;设计现代OS的主要目标是&#xff1a;方便性、有效性、可扩充性、开放性 2、OS的作用可表现在哪几个方面&#xff1f; 答&#xff1a;&#xff08;1&#xff09;从一…

每个软件测试人员必须具备的12大技能

作者 | Kiran Beladiya 赛希翻译组 译 作为一名软件测试员&#xff0c;掌握一些技术技能是非常必要的&#xff0c;这可以使应用程序变得更好。让我们来看看对任何软件测试员来说必不可少的技能。 没有人能成为这样的软件测试员。要获得这个职业&#xff0c;每个测试人员都必…

公文写作技巧:作风建设类排比句40例

1.面对突发任务时&#xff0c;是主动请缨还是被动服从&#xff1b;遇到棘手问题时&#xff0c;是迎难而上还是推诿回避&#xff1b;在荣誉面前&#xff0c;是正确对待还是邀功请赏&#xff1b;汇报工作时&#xff0c;是真实客观还是弄虚作假。 2.不是敷衍了事图轻松&#xff0…

Spring、SpringMVC

文章目录 Spring一、Spring概述二、Spring快速入门1. Spring开发步骤2. Spring配置文件2.1 Bean标签基本2.2 Bean标签范围2.3 Bean生命周期2.4 Bean实例化三种方式 3. Bean的依赖注入3.1 Bean依赖注入概念3.2 Bean依赖注入方式3.3 Bean的依赖注入的数据类型3.4 引入其他配置文件…

Visual Studio 2022使用CMake+MinGW+Clang+LLDB作为开发环境

笔者前面写了两篇关于Visual Studio 2022使用MinGW的博文&#xff1a;《Visual Studio 2022使用MinGW来编译调试C/C程序》、《Visual Studio 2022 CMakeMinGWGDB 调试目标程序》&#xff0c;这两篇博文都是介绍的是GCCGDB的编译与调试&#xff0c;本文笔者介绍的则是ClangLLDB的…

微服务框架 01SOA和传统服务与微服务的差别

SOA思想 1.SOA思想介绍 面向服务的架构&#xff08;SOA&#xff09;是一个组件模型&#xff0c;它将应用程序的不同功能单元&#xff08;称为服务&#xff09;进行拆分&#xff0c;并通过这些服务之间定义良好的接口和协议联系起来。接口是采用中立的方式进行定义的&#xff0c…

20行代码来爬取某某云的榜单音乐

今天来爬爬音乐&#xff0c;一丝丝的无聊 前期准备 软件环境 Python3.8pycharm 模块 requests、re、os 三个 其中requests是第三方模块需要手动安装一下 re、os都是内置模块&#xff0c;不需要安装 浏览器开发者工具 咱们需要学会如何使用开发者工具。 对此很多小伙伴都…

基于Spring Boot的仿豆瓣平台

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 后端为了提高性能和用户体验&#xff0c;该系统平台使用Spring Boot集合Spring&#xff0c;Spring MVC和MyBatis框架做基础&#xff0c;并且集成Spring Data框架&#xff0c;MySQL做数据持久化&#xff0c;Redis缓存提高速度&…

专业解读财务共享实现财务数智化转型的有效路径

近年来&#xff0c;随着数字经济的飞速发展&#xff0c;各大企业全面开启数智化转型之路&#xff0c;作为企业数智化转型的重要内容&#xff0c;财务数智化转型始于财务共享服务。然而&#xff0c;财务共享建设并不是一蹴而就的&#xff0c;如何通过财务共享实现财务数智化转型…

Linux安装与配置ansible

文章目录 Linux安装Ansible一、安装ansible二、配置管理节点和远程主机的连接使用ssh-keygen生成密钥复制SSH密钥到远程主机验证SSH配置 三、主机清单配置文件四、Ansible的配置文件 Linux安装Ansible 在Linux上安装Ansible可以通过以下步骤完成&#xff1a; 一、安装ansible…

npm更换成淘宝镜像源及cnpm使用

1.需求由来 由于node安装插件是从国外服务器下载&#xff0c;受网络影响大&#xff0c;速度慢且可能出现异常。所以如果npm的服务器在中国就好了&#xff0c;所以我们乐于分享的淘宝团队&#xff08;阿里巴巴旗下业务阿里云&#xff09;干了这事。来自官网&#xff1a;“这是一…

Python常见错误(Error)一览大全——初学者必看

路漫漫其修远兮&#xff0c;学习python任重而道远&#xff0c;对于初学者来说&#xff0c;最难受的就是报错&#xff0c;其次是错误翻译好了&#xff0c;可是又不会改了&#xff0c;那么今天&#xff0c;我已IKUN老师的身份&#xff0c;结合我们常见的错误&#xff0c;做一个常…

堆排序之——TopK问题

思维导图&#xff1a; 一&#xff0c;TopK算法的运用 TopK的算法在我们的日常生活中可谓是大有用处&#xff0c;比如你在点外卖时外卖榜单上的销量前几名的筛选&#xff0c;富豪排行榜的榜单人物的筛选&#xff0c;游戏排位……等等领域都会有TopK算法的涉及。TopK问题的用处可…

javaWeb ssh旅游景点网站系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh旅游景点网站系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0…

类型转换-Java 如何计算两个时间的差

一、背景&#xff1a; 今天一个小伙伴在开发中&#xff0c;常取不到数&#xff0c;像string转换int,int转换string 虽然好像只是倒过来了&#xff0c;但是实现的逻辑不一样&#xff0c;今天就是日期在计算过程中的转换做一个总结 二、步聚 1.JAVA中与日期时间相关的类 1.1j…

聚合函数(基础版)

QUESTION ONE: # Write your MySQL query statement below select id,movie,description,rating from cinema where description <> boring and mod(id,2) 1 order by rating desc很简单的两个条件&#xff0c;一个通过 <> 解决不等于的情况&#xff0c;而确定奇…

java基础知识一

1、Java语言概述 1、java的出现标志着真正的分布式系统的到来 2、Java与c的区别 2.1、全局变量 Java中没有全局变量&#xff0c;使用类中的公共的静态变量作为这个类的全局变量 2.2、指针 Java中没有任何在指针操作 2.3、条件转移指令 Java中没有goto语句&#xff0c;通…

【day 01】初始vue

Vue的相关背景&#xff1a; vue2 > vue3 >vue实战 vue Taylor otwell (程序员中的网红) 框架 库 &#xff08;功能 方法&#xff09;axios 框架 生态 引入第三方功能库 社区 Vue2 Vue3 需要准备的小工具 vscode : snipper Vetur 浏览器需要准备 Vue Devtools Vue 引入方式…

nvm版本控制工具安装及使用

一、nvm介绍 nvm全英文也叫node.js version management&#xff0c;是一个nodejs的版本管理工具。nvm和n都是node.js版本管理工具&#xff0c;为了解决node.js各种版本存在不兼容现象可以通过它可以安装和切换不同版本的node.js。 二、nvm下载安装及使用 2.1 nvm下载 安装包…

【C++】容器篇(三)—— stack的基本介绍及其模拟实现

前言&#xff1a; 在之前的学习中我们已经了解了 vector 和 list &#xff0c;今天我将带领学习的是关于STL库中的 stack的学习&#xff01;&#xff01;&#xff01; 目录 &#xff08;一&#xff09;基本介绍 1、基本概念 2、容器适配器 &#xff08;二&#xff09;基本使…