链表经典OJ题(链表回文结构,链表带环,链表的深拷贝)

news2025/1/9 1:31:54

目录

前言

1.反转一个单链表。 

2.   给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

3.链表的回文结构。

 4.链表带环问题(*****)

4.1是否带环

4.2 入环的节点

5.随机链表的复制(链表的深拷贝)


前言

        前面我们学习了链表,现在我们来手撕几道经典链表OJ题目吧!!!


1.反转一个单链表。 

题目链接206. 反转链表 - 力扣(LeetCode)

题解:

        在这一题,我们定义了三个指针变量,首先让prev指向NULL,prev的作用是保存cur的前面的一个节点,next是保存cur后面的节点。

        每一次循环迭代,都让cur指向前面的节点,也就是指向prev;

        再让prev去到cur的位置,cur去到next位置,最后再让next去到cur->next的位置,这样就完成了一次循环迭代。直到cur为NULL;
 

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode*prev = NULL;
    struct ListNode*cur = head;
    struct ListNode*next =head;
    while(cur)
    {
        next = cur->next;
        cur->next = prev;
        prev =cur;
        cur = next;
    }
    return prev;
}

        这样就通过了!

      


2.   给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

题目链接:876. 链表的中间结点 - 力扣(LeetCode)


 

题解:

        这题思想其实非常简单,既然让返回中间节点,那么我们就定义两个指针,fast和slow,让fast走两步,slow走一步,这样fast走完全程之后,slow就只走了一半。

        需要注意的是,节点总数为奇数时,fast走到最后一个节点就结束,而节点总数为偶数时,fast节点就要走到NULL。因此结束条件就要写成(fast&&fast->next)。

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* slow = head,*fast = head;
    while(fast&&fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }

    return slow;
}

3.链表的回文结构。

题目链接:链表的回文结构_牛客题霸_牛客网 (nowcoder.com)


 题解:

        这一题看似复杂,实际不难。我们只需要找到中间节点,然后从中间节点反转链表 ,再分别从两个头开始遍历,若每个节点都相等,则为回文结构。

        如果是奇数个,两条链表节点数量会不会不想等呢?

        不会!因为A链表的最后一个并没有与B链表的最后一个节点断开,所以两链表有一个 公共节点,因此在奇数个节点下,两链表节点个数也相同,结束条件显而易见为:(head&&rhead)。

class PalindromeList {
public:
struct ListNode* reverseList(struct ListNode* head) {//反转链表
    struct ListNode*prv = NULL;
    struct ListNode*cur = head;
    struct ListNode*n =head;
    while(n)
    {
        n = cur->next;
        cur->next = prv;
        prv =cur;
        cur = n;
    }
    return prv;
}
struct ListNode* middleNode(struct ListNode* head){//找中间节点
    struct ListNode* slow = head,*fast = head;
    while(fast&&fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }

    return slow;
}
    bool chkPalindrome(ListNode* A) {
        ListNode* mid = middleNode(A);
        ListNode*rhead = reverseList(mid);
        while(A&&rhead)
        {
            if(A->val!=rhead->val)
                return false;
            A=A->next;
            rhead=rhead->next;
        }
        return true;
    }    
};


 4.链表带环问题(*****)

        链表带环问题是链表中非常重要的一类问题,在企业面试中也会经常遇到。此类问题有两种,第一种是判断链表是否带环,第二种是判断链表开始入环的节点是哪个。


4.1是否带环

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

题解:我们不禁思索,该如何判断链表是否带环呢?

        在这里我们可以定义两个指针fast和slow,让fast先走,如果到最后还能与slow相遇,那就证明该链表是带环的。在此就引出了一个问题,fast要比slow快多少?

        1.slow一次走一步fast一次走两步一定会相遇吗?

        答案是一定会相遇,因为fast和slow的距离每次都缩减1,到最后一定会减到0。

        2.slow一次走一步fast一次走三步一定会相遇吗?

        答案是不一定,如果N为偶数,fast和slow的距离每次都缩减2,最后一定会减到0。如果为奇数,最后会减到-1,这样就又开始新一轮的追击了,而且永远不会相遇。

        3.slow一次走n步fast一次走m步一定会相遇吗?(m>n>1)

        最后我们得到2L = n*C-N最后一定得到的是一个奇数,所以最后一定能追上。

bool hasCycle(struct ListNode *head) {
    struct ListNode* fast = head,*slow =head;
    while(fast&&fast->next)
    {
        fast =fast->next->next;
        slow =slow ->next;
        if(fast ==slow)
            return fast;
    }
    return NULL;
}

4.2 入环的节点

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

题解:这一题与上一题是不一样的,这一题是要找到入环的节点,从哪个节点开始入环,这题难度相较于上一题显然是上升了。

        假设,fast和slow在meet点相遇,那么slow就走了(L+X)的距离,fast就走了(L+X+n*C)的距离,最后由图上等式可得,L=n*C-X,那也就是说,如果相同速度的指针,一个从相遇点开始走,另一个从入口点开始走,他们到入口与点的距离是一样的,所以一定会在入口点相遇。

        因此本题思路就出来了:1.找到相遇点 2.让相同速度的指针,一个从相遇点开始走,另一个从入口点开始走。最终就一定会相遇。

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *slow = head,*fast =head;
    while(fast&&fast->next)
    {
        slow = slow->next;
        fast= fast->next->next;
        if(slow == fast)
        {
            struct ListNode* meet= slow;
            while(head!=meet)
            {
                head = head->next;
                meet =meet->next;

            }
            return meet;
        }
    }
    return NULL;
}

5.随机链表的复制(链表的深拷贝)

题目链接:138. 随机链表的复制 - 力扣(LeetCode)

题解:链表的深拷贝,是链表中较难的问题,但如果把思路理清,问题也就迎刃而解了。

        我们的第一思路可能就是将每个节点的信息先拷贝下来,然后我们来处理random的指向的时候,可能就是用嵌套循环将每个节点的random进行比较,来确定指向,这样一来就造成时间复杂度到达O(N^2)了,这就不符合题目要求了。

        那么我这里就提供一种可行的思路:

                1.拷贝的节点都插入在原来节点的后面(如图)

                2.处理random的指向

        我们可以清楚的看到,原节点的下一个节点就是我们所拷贝的节点,那么让本来指向原节点random,指向原节点的下一个是不是就可以让拷贝节点的random完成正确的指向,这就解决了然random指向的问题了。如图(我们已经得到所有的拷贝节点了。)

                3.copy的节点一个一个的解下来尾插就可以得到我们想要的深拷贝出来的链表了。

完整代码:

truct Node* copyRandomList(struct Node* head) {
	struct Node* cur =head;
    while(cur)
    {
        struct Node*copy= (struct Node*)malloc(sizeof(struct Node));
        copy->val =cur->val;
        copy->next = cur->next;
        cur->next = copy;
        cur=cur->next->next;
    }
    cur =head;
    while(cur)
    {
        struct Node*copy= cur->next;
        if(cur->random ==NULL)
            copy->random =NULL;
        else
            copy->random = cur->random->next;
        cur = cur->next->next; 
    }
    struct Node* newhead = NULL,*fail=NULL;
    cur =head;
    while(cur)
    {
        struct Node*copy = cur->next;
        struct Node*next =copy->next;
        if(newhead==NULL)
        {
            newhead = fail = copy;
        }
        else
        {
            fail->next = copy;
            fail=fail->next;
        }
            
        cur->next = next;
        cur = next;
    }
    return newhead;
}

这里都是链表比较经典的题目,希望对你有所帮助!!!

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

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

相关文章

[ARM入门]ARM模式及其切换、异常

ARM技术特征 ARM处理器有如下特点 体积小、功耗低、成本低、性能高支持Thumb(16位)/ARM(32位)双指令集,能很好地兼容8位/16位器件大量使用寄存器,指令执行速度更快大多数数据操作都在寄存器中完成寻址方式…

亚马逊云AI应用科技创新下的Amazon SageMaker使用教程

目录 Amazon SageMaker简介 Amazon SageMaker在控制台的使用 模型的各项参数 pytorch训练绘图部分代码 Amazon SageMaker简介 亚马逊SageMaker是一种完全托管的机器学习服务。借助 SageMaker,数据科学家和开发人员可以快速、轻松地构建和训练机器学习模型&#…

基于STM32单片机抢答器设计

**单片机设计介绍, 基于STM32单片机抢答器设计-Proteus仿真 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于STM32单片机的抢答器设计可以用于教育和培训场景中的抢答游戏或考试环节。以下是一个基本的介绍设计步骤…

翻译环境(编译和链接)(简单讲解,理解图就行)

前言 这是我们学习代码的最重要的一个知识点之一,因为我们要去运行一个代码并不是简单的去直接出结果,而是经过了很多我们看不到的步骤,我们在这里以C语言为例子在Linux的环境下讲解,大家没有学过Linux的不用担心,最后…

creo6.0教程之旋转,扫描

目录 一、旋转:二、扫描: 一、旋转: 案例1:旋转一个球: 任意一个平面绘制草图: 确定草图后,然后退出草图,点击旋转: 案例2:旋转一个杯子雏形: …

Clickhouse学习笔记(11)—— 数据一致性

使用合并树引擎时,无论是ReplacingMergeTree还是SummingMergeTree,都只能保证数据的最终一致性,因为数据的去重、聚合等操作会在数据合并的期间进行,而合并会在后台以一个不确定的时间进行,因此无法预先计划&#xff1…

【Redis】redis的下载安装

目录 1.window安装 2.Linux安装 下载 解压 移动redis目录 编译 1.window安装 在github 下载redis的安装包 https://github.com/microsoftarchive/redis/releases 下载完后安装相应的目录下,比如我是放在c盘的Program Files下 开启redis,双击运行…

Java必刷入门递归题×5(内附详细递归解析图)

目录 1.求N的阶乘 2.求12...N的和 3.顺序打印数字的每一位 4.求数字的每一位之和 5.求斐波拉契数列 1.求N的阶乘 (1)解析题目意思 比如求5的阶乘,符号表示就是5!;所以5!5*4*3*2*1我们下面使用简单的…

C++套接字库sockpp介绍

sockpp是一个开源、简单、现代的C套接字库,地址为:https://github.com/fpagliughi/sockpp,最新发布版本为0.8.1,license为BSD-3-Clause。目前支持Linux、Windows、Mac上的IPv4、IPv6和Unix域套接字。其它*nix和POSIX系统只需很少的…

冯·诺伊曼体系结构--操作系统

文章目录 1.认识冯诺依曼系统1.1约翰冯诺依曼1.2冯诺依曼结构1.3存储器的读写速度1.4对冯诺依曼结构的认识1.5冯诺依曼结构在生活中的演示 2.操作系统--“搞管理”的软件2.1概念2.2OS存在的意义2.3管理的方式2.4系统调用和库函数概念 1.认识冯诺依曼系统 1.1约翰冯诺依曼 1.2冯…

【论文】利用移动性的比例公平蜂窝调度测量和算法

(一支笔一包烟,一节论文看一天 )(一张纸一瓶酒,一道公式推一宿) 摘要1. 引言2. 相关工作3. 模型和问题公式4. 预测FPF调度 ( P F ) 2 S (PF)^2S (…

js 加密解密 cryptojs(对称加密库)

js 加密解密可以使用 crypto-js 这是一个对称加密的库, 可以使用 AES DES 但没有 rsa 等非对称加密的方法 安装方法 npm install crypto-js 它可以进行 MD5 SHA-1 SHA-256 Base64 AES DES 等算法和加密 import crypto from "crypto-js"let md5binary cry…

通过防火墙禁止访问指定网站(个人电脑,Windows系统)

背景 近年沉迷B站视频不能自拔,使用了诸多手段禁用,都很容易破戒。为了彻底杜绝B站的使用,决定手动进行设置。在ChatGPT和文心一言提问,得到了以下四种方法(按个人认为的戒断水平由低到高排序):…

AI驱动的软件测试,何时可以信赖?

综合编译|TesterHome社区 作者|Yuliya Vasilko,数据工程师 以下为作者观点: 越来越多的组织转向人工智能(AI)驱动的测试解决方案,以简化质量保证流程并提高软件可靠性。 随着对人工智能的依赖程…

HDRP图形入门:HDRP渲染管线depth翻转

新项目开坑HDRP渲染管线,花了些时间把项目开发框架和图形工作流更新到最新版本,其间发现HDRP中深度信息和buildin渲染管线翻转了。 以前的buildin渲染管线,距离摄像机越近depth->0,越远depth->1,这也很好理…

JAVA毕业设计110—基于Java+Springboot+Vue的房屋租赁系统小程序(源码+数据库)

基于JavaSpringbootVue的房屋租赁系统小程序(源码数据库)110 一、系统介绍 本系统前后端分离 本系统分为用户、房东、超级管理员三种角色 1、用户: 登录、注册、房屋搜索、房屋收藏、看房预约、租房申请、租房记录、看房记录、收藏记录、我的消息、个人信息修改…

js动态显示当前时间

目录 1、封装时间函数 2、在页面写一个div标签,用来存放时间 3、获取div标签,开启定时器,时间为1000ms 4、先调用时间函数,防止页面加载延迟,再在定时器里调用 完整代码 效果图 1、封装时间函数 function getTi…

美团2024届秋招笔试第二场编程真题-小美的数组构造

分析:暴力角度看,因为数组a和b总和一样,所以实际上是将总和m划分为n个数字,且每个数字都和a数组不一样的方案数。当然会超时。从数据角度看,平方级别算法是可以的。 其实用动态规划的四步法分析起来还是很简单的&…

游戏平台采集数据

首先,你需要在你的项目中添加Kotlin的网络库,例如OkHttp。你可以在你的build.gradle文件中添加以下依赖: dependencies {implementation com.squareup.okhttp3:okhttp:4.9.0 }然后,你可以使用以下代码来创建一个基本的网络爬虫&a…

数据库安全:MySQL 身份认证漏洞(CVE-2012-2122)

数据库安全:MySQL 身份认证漏洞(CVE-2012-2122) MySQL 身份认证漏洞是一个身份认证绕过漏洞,该漏洞的核心原理涉及到 MySQL 在处理身份认证时的一个安全缺陷,这个漏洞可以使攻击者可以绕过安全身份认证,从…