三个有意思的链表面试题的完成

news2024/10/6 16:30:40

上一篇博客我们已经完成了链表的所有内容,那么这一篇博客我们来看一下三个特别有意思的链表题目。

**第一个题目如下:**

在这里插入图片描述
在这里插入图片描述
相信不少朋友看到这题目就已经晕了,那就简单说明下这个题目,题目就是创建一个链表,其中每个节点有两部分–指针域与数值域,指针域里也有两个指针next(指向下一个节点),random(随机指向),要求我们拷贝一份这个链表,使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
在这里插入图片描述

也就是上图的形式,这个题目如果单纯的只拷贝一份链表和每个节点的val,相信大家可以很快的做出,也就是遍历一下原链表,遍历一个节点创建一个新的节点并拷贝值,最后将节点连接形成链表即可。但现在增加了一个random指针,我们该如何解决这个问题呢?

受限于当前的知识,我们可用的方法很少,下面是一个很巧妙的思路:
1、创建新的节点,构造新链表
在这里插入图片描述
我们可以遍历一个节点拷贝一个节点,并且将这个新的节点插入至原节点的后面。

2、完成random的指向
在这里插入图片描述
当我们把这一步以图像的形式展现,我们就可以发现新链表当前节点的random指针是不是指向原链表原节点的random->next指向的节点

3、取下拷贝的节点,形成题目要求的链表
在这里插入图片描述
把这个节点连接形成新的链表,我们可以使用之前学过的尾插,头插都是可以的。

最后还有一个小细节,就是如果我们只取下节点,那原链表是不是被我们断开了,我们可以恢复原链表的结构也可以不恢复,题目里没有说明就不用管。

代码如下:

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */
struct Node* copyRandomList(struct Node* head) {
	struct Node*pcur=head;//创建遍历原链表的指针pcur
    while(pcur)
    {
        struct Node*newnode=(struct Node*)malloc(sizeof(struct Node));
        newnode->val=pcur->val;
        newnode->next=pcur->next;
        pcur->next=newnode;
        pcur=newnode->next;
    }//这一部分就是拷贝节点,并插入原节点后面
    struct Node*cur=head;//同样为遍历链表的节点
    while(cur)
    {
         struct Node*newnode=cur->next;
        if(cur->random==NULL)
        {
            newnode->random=NULL;
        }
        else{
            newnode->random=cur->random->next;
        }
        cur=newnode->next;
    }//这一部分完成的是新节点的random的指向
    struct Node*phead=NULL;//创建一个新的链表phead为头指针,ptail为尾指针
    struct Node*ptail=NULL;
    struct Node*Cur=head;
    while(Cur)
    {
        struct Node*node=Cur->next;//node指向的是原链表的新节点
        struct Node*next=node->next;//next指向的是原链表的原节点
        if(ptail==NULL)//如果新链表为空
        {
            phead=ptail=node;
        }
        else//链表不为空
        {
           ptail->next=node;
           ptail=ptail->next;
        }
        Cur=next;
    }
    return phead;//返回新链表的头

}
**第二个题目如下:**

在这里插入图片描述
在这里插入图片描述
这道题目代码比较简单,想要理解透彻还是有一定难度的。

思路如下:
在这里插入图片描述
就是使用快慢指针,快指针一步走两个节点,慢指针一步走一个节点,让慢指针去追这个快指针,当追上的时候也就是fast==slow,那就证明带环,如果一直追不上那就不带环。

那一定追的上吗?有没有可能出现错过的情况?快指针可以一步走三个节点吗?走三个节点会不会错过呢?这几个问题就是我们现在需要解决的。

第一个问题:那一定追的上吗?有没有可能出现错过的情况?

在这里插入图片描述
从现在开始,fast走两步,slow走一步,那么两指针每走一步,它们之间的距离减小1,所以N取任何值slow与fast指针都会相遇,故不存在错过的情况。

第二个问题:快指针可以一步走三个节点吗?走三个节点会不会错过呢?

由上面的图我们可以推出:
在这里插入图片描述
那么我们可以总结一下:
当N为偶数时,无论R为奇数偶数,都能够追上,也就是不会错过。
当N为奇数,R为奇数时,能够追上;
当N为奇数,R为偶数时,永远追不上。

但是存不存在N为奇数,R为偶数这种情况?
在这里插入图片描述
由上面得出的结论就是fast一步走三个节点,一定能追上。

根据上面的推导过程,fast一步走4个节点、5个节点都是可以推出来的。

代码实现很简单:

/**
 * 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;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            return true;
        }
    }
    return false;
}
**第三个题目:**

在这里插入图片描述
这个题目就是在上一个题目的基础上更加深入一点,需要我们返回这个循环的初始节点;

第一步:判断环的有无
因为这一步与上一个题目基本一样,所以我这里就不再重复了;

第二步:让slow走到fast的位置,也就是让两个指针相遇定义为meet,返回当前节点,这一步也可以通过前一个题目实现;

第三步:让pcur从链表的头开始走,同时meet也开始在环内走,当两者相等时,两指针指向的节点就是开始循环的节点。

下面我们就来讨论为什么:
在这里插入图片描述
代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode*fastnode(struct ListNode*head)
{
    struct ListNode*fast=head;
    struct ListNode*slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow==fast)
        {
            return fast;//这里我没有创建新的meet指针,当两者相等时,返回其中一个效果相同
        }
    }
    return NULL;//判断是否有环
}

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*fast=fastnode(head);
    if(fast==NULL)//如果链表没有环就直接返回NULL
    {
        return NULL;
    }
    struct ListNode*slow=head;
    while(slow!=fast)//这一步就是让两指针相遇,返回相遇时的节点,也就是环开始的节点
    {
        slow=slow->next;
        fast=fast->next;
    }
    return fast;
}

最后一个题还有一种做法,那就是将meet指向的节点断开,那现在整个题目就变为了相交链表求相交节点的问题了,这里只简单的说明一下思路,有兴趣的可以下来实现一下;
在这里插入图片描述

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

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

相关文章

比勤奋更重要的是系统思考的能力

不要在接近你问题症状的地方寻找解决办法,要追溯过去,查找问题的根源。通常,最有效的活动是最微妙的。有时最好按兵不动,使系统自我修正,或让系统引导行动。有时会发现,最好的解决办法出现在完全出乎预料的…

Redis 实战 - 缓存异常及解决方案

文章目录 概述一、缓存穿透1.1 缓存穿透是什么1.2 解决方案 二、缓存击穿2.1 缓存击穿是什么2.2 解决方案 三、缓存雪崩3.1 缓存雪崩是什么3.2 解决方案 四、拓展4.1 缓存预热4.2 缓存降级 五、结语 把今天最好的表现当作明天最新的起点…….~ 概述 在实…

【漫画算法】哈希表:古代皇帝的秘密魔法书

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣! 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航: LeetCode解锁100…

如何确保大模型 RAG 生成的信息是基于可靠的数据源?

在不断发展的人工智能 (AI) 领域中,检索增强生成 (RAG) 已成为一种强大的技术。 RAG 弥合了大型语言模型 (LLM) 与外部知识源之间的差距,使 AI 系统能够提供更全面和信息丰富的响应。然而,一个关键因素有时会缺失——透明性。 我们如何能够…

Android窗口管理

一 概述 本篇文章主要讲 Window、WindowManager、WindowManagerService 三者之间的关系及其运行机制。总的来说 Window 表示的是一种抽象的功能集合,具体实现为 PhoneWindow。WindowManager 是外界访问 Window 的入口,对 Window 的访问必须通过 Window…

状态转换图

根据本章开头讲的结构化分析的第3条准则,在需求分析过程中应该建立起软件系统的行为模型。状态转换图(简称为状态图)通过描绘系统的状态及引起系统状态转换的事件,来表示系统的行为。此外,状态图还指明了作为特定事件的结果系统将做哪些动作(例如,处理数据)。因此,状态图提供了…

【轻松压缩,一键搞定】您的图片处理神器来了!

压图地址 一个功能强大的图片处理工具,它可以满足用户对于图片压缩、格式转换、质量调节以及长图片分割等多种需求。 【轻松压缩,一键搞定】您的图片处理神器来了! 🎉 您是否曾为图片太大无法上传而烦恼?是否为图片格…

rk3568_atomic

文章目录 前言一、atomic是什么?二、原子操作API函数1.atomic原子操作2.原子位操作API三、atomic驱动实验总结前言 本文记录的是正点原子rk3568开发板的atomic实验 一、atomic是什么? 不同的线程在进行读写的过程中,可能会冲突乱入,导致会有预想不到的结果。所以为了让数…

信息系统项目管理师0131:输出(8项目整合管理—8.7监控项目工作—8.7.3输出)

点击查看专栏目录 文章目录 8.7.3 输出8.7.3 输出 工作绩效报告工作绩效信息可以用实体或电子形式加以合并、记录和分发。基于工作绩效信息,以实体或电子形式编制形成工作绩效报告,以制定决策、采取行动或引起关注。根据项目沟通管理计划,通过沟通过程向项目干系人发送工作绩…

文档档案管理系统整体建设方案书(实际项目原件word2024)

1.系统概述 1.1.需求描述 1.2.需求分析 1.3.重难点分析 1.4.重难点解决措施 2.系统架构设计 2.1.系统架构图 2.2.关键技术 数据备份技术 3.系统功能设计 3.1.功能清单列表 3.2.基础数据管理 3.3.位置管理 3.4.文档使用 3.5.文档管理 软件全套资料包获取方式①:软件项…

[windows系统安装/重装系统][step-4][番外篇-2]N卡驱动重装 |解决:开机几小时后电脑卡顿 | 后台自动运行了上千个Rundll32进程问题

现象 开机几小时后,电脑变卡,打开后台管理器都卡,后台管理去转圈圈一小会儿后看到后台进程上千个,好多个Rundll32进程 重启下运行会稍快 重启后运行快,后台管理器反应也快 打开后台管理器不卡(几小时后打…

Hadoop3:HDFS中DataNode与NameNode的工作流程

一、DataNode中的数据情况 数据位置 /opt/module/hadoop-3.1.3/data/dfs/data/current/BP-823420375-192.168.31.102-1714395693863/current/finalized/subdir0/subdir0块信息 每个块信息,由两个文件保存,xxx.meta保存的是数据长度、校验和、时间戳&am…

基于Java、SpringBoot和uniapp在线考试系统安卓APP和微信小程序

摘要 基于Java、SpringBoot和uniapp的在线考试系统安卓APP微信小程序是一种结合了现代Web开发技术和移动应用技术的解决方案,旨在为教育机构提供一个方便、高效和灵活的在线考试平台。该系统采用Java语言进行后端开发,使用SpringBoot框架简化企业级应用…

netmask一键修改子网掩码(KALI工具系列八)

目录 1、KALI LINUX简介 2、netmask工具简介 3、在KALI中使用netmask 3.1 目标主机IP(win) 3.2 KALI的IP 4、命令示例 4.1 查看版本 4.2 修改etho的子网掩码 4.3 查看状态信息 4.4 查看子网掩码 4.5 查看范围 4.6 DNS查看 5.、总结 1、KAL…

【实际项目精选源码】ehr人力资源管理系统实现案例(java,vue)

一、项目介绍 一款全源码可二开,可基于云部署、私有部署的企业级数字化人力资源管理系统,涵盖了招聘、人事、考勤、绩效、社保、酬薪六大模块,解决了从人事招聘到酬薪计算的全周期人力资源管理,符合当下大中小型企业组织架构管理运…

Redis可视化工具:Another Redis Desktop Manager下载安装使用

1.Github下载 github下载地址: Releases qishibo/AnotherRedisDesktopManager GitHub 2. 安装 直接双击exe文件进行安装 3. 连接Redis服务 先启动Redis服务,具体启动过程可参考: Windows安装并启动Redis服务端(zip包&#xff09…

Linux -- 进程间通信的五种方式

IPC(InterProcess Communication)的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中Socket和Stream支持不同主机上的两个进程IPC。 管道(Pipes)&#xff1a…

618快到了,送大家一款自动化脚本工具,一起薅羊毛

前言 一年一次的618活动来了,大家做好准备了,奇谈君为大家准备好用的618神器,解放双手,简单操作就可以把红包拿到手。 京淘自动助手 首次使用前需要进行设置 将手机的无障碍权限和悬浮窗权限打开 设置完成后,可以把…

编程实战:类C语法的编译型脚本解释器(四)总入口和使用方法

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 系列入口: 编程实战…

深入了解数据库设计中的规范化与反规范化

目录 零、前言 一、一些基本术语 二、关系模式 2.1. 什么是关系模式 2.2. 示例 三、数据依赖 3.1. 函数依赖 3.1.1. 完全函数依赖 3.1.2. 部分函数依赖 3.1.3. 传递函数依赖 3.2. 多值依赖 3.3. 连接依赖 四、规范化 4.1. 第一范式(1NF) …