LeetCode 牛客单链表OJ题目分享

news2024/11/14 20:33:38

目录

  • 链表的回文结构
  • 相交链表
  • 环形链表I
  • 环形链表II

链表的回文结构

链接: link
题目描述:
在这里插入图片描述
题目思路:
本题思路是找到每一条链表的中间节点,之后逆置中间节点之后的链表,定义两个指针,分别指向逆置后链表的头部的链表的中间节点,依次进行比对,如果比对过程中两个节点的值不相等则返回false,比对结束后证明该链表是回文结构,返回true。

步骤1:找到链表的中间节点这里是引用
方法:快慢指针,slow和fast指针
情况1:链表节点个数为偶数个,slow一次走一步,fast一次走两步,结束条件是fast为空,则slow指向的则是要找的mid节点。
情况2:链表节点个数为奇数个,slow一次走一步,fast一次走两步,结束条件是fast->next为空,则slow指向的则是要找的mid节点。
步骤2:逆置链表中间节点后的节点
在这里插入图片描述
方法:

方法1思路:
这力我们需要三个指针n1 n2 n3方便我们进行迭代
在这里插入图片描述
初始化n1指向NULL,n2指向第一个节点,n3指向第2个节点,下面是n1 n2 n3 3个指针移动的过程。
1、改变第一个指针n1的指向,链表反转后,第一个节点的指针域指向的是NULL,就上图来看,也就是n2->next=n1;
在这里插入图片描述
2、改变指向后,我们接下来的操作就是移动3个指针继续进行链接变向的操作。下面是如何变动三个指针的过程:
将n2的值赋给n1,n3的值赋给n2,n3再向下走一步。
在这里插入图片描述
3、下面进行的步骤就是反转链接方向:n2->next = n1。
在这里插入图片描述

上述过程就是我们反转的最核心步骤,下面是本题循环终止条件和Bug点:

这里我们要注意,本题要清楚的是,当n1指向最后一个节点的时候,循环就终止了,但是这个点并不是我们所需要的循环的终止条件,循环终止条件是n2为空指针
在这里插入图片描述
本题大致雏形就出来了,但是我们实际进行运行的时候,还会出现空指针的问题,问题的来源就在于n3
在这里插入图片描述
当n2不为空指针,并且n2此时已经指向最后一个节点时,n3已经为空指针,当n2为空指针的时候,n3也要向下走,这就造成了空指针的问题,所以我们要进行处理的是n3,n3不为空指针的时候,n3才可以继续向下走。
最后状态如下图所示:最后我们只需要返回n1就可以了

疑问点:
偶数个节点循环终止的条件是当mid节点为空,也就是下面情况:
在这里插入图片描述
但是奇数节点就会出现下面的情况:
在这里插入图片描述
这里我们只要记住虽然我们逆置了mid之后的链表,但是我们并没有改变2节点之后链接的是3节点,所以这里我们不用进行处理,继续让两个指针向下走,直到mid指向空,循环结束。
代码实现:

struct ListNode* reverseList(struct ListNode* head) {
    if(head == NULL || head->next == NULL)
        return head;
    
    struct ListNode* n1, *n2, *n3;
    n1 = head;
    n2 = n1->next;
    n3 = n2->next;
    n1->next = NULL;
    //中间节点不为空,继续修改指向
    while(n2)
    {
        //中间节点指向反转
        n2->next = n1;
        //更新三个连续的节点
        n1 = n2;
        n2 = n3;
        if(n3)
            n3 = n3->next;
    }
    //返回新的头
    return n1;
}
struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* slow = head;
    struct ListNode* fast = head;

    while(fast!=NULL && fast->next != NULL)
    {
       slow = slow->next;
       fast = fast->next->next;
    }

    return slow;
}
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        struct ListNode* mid = middleNode(A);
        struct ListNode* rmid = reverseList(mid);
        struct ListNode* head = A;
        while(rmid)
        {
            if(head->val!=rmid->val)
            {
                return false;
            }
            else 
            {
                head = head->next;
                rmid = rmid->next;
            }
        }
        return true;
    }
};

相交链表

链接: link
题目描述:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题目思路:
本题首先要明确下图的相交是绝对不会出现的:
在这里插入图片描述
解释:因为上图中相交节点没有两个指针域,所以说一旦两条链表相交,那么必然是下图情况:
在这里插入图片描述

判断两条链表相交的方法:
两条链表尾指针相等(这里是尾指针并不是尾节点值相等),如果尾指针相等,则证明两条链表相交,那么接下来的步骤就是求交点,如果尾指针不相等,则返回NULL。
如何求交点:
这里我们要明确,一旦到求交点这步,就证明一定会有交点,因为无交点的情况已经返回NULL。
这里仍然是一个快慢指针的问题,因为两条链表长度不相同,所以无法在求交点的时候指向同一个节点,这时就需要调整快慢指针,在调整快慢指针之前先求出两条链表的长度lenA和lenB,让长链表的指针先走(lenA-lenB)步,再两个指针同时出发,判断两指针地址是否相等,相等则返回。
1、求两条链表节点个数:循环结束条件tailA->next=NULL****tailB->next=NULL,lenA和lenB初始值为1
2、这里为了减少本题代码冗余,在求出abs(lenA-lenB)(abs是库函数,用abs求出的值是该数的绝对值)之前首先定义两个结构体指针longList和shortList,假设第一条链表长度是最长的,两指针赋初值longList = headA,shortList=headB,判断如果lenB>lenA,则更改初值longList = headB,shortList=headA,这里的目的是减少代码冗余。
在这里插入图片描述
让longList先走abs(lenA-lenB)步:
在这里插入图片描述
此时两指针同时向下移动,判断两指针地址是否相等(循环条件),相等则返回longList(shortList)。
在这里插入图片描述

代码实现:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
    //判断链表当中是否存在相交节点,如何判断相交?尾指针地址相同。
    struct ListNode* tailA=headA;
    struct ListNode* tailB=headB;
    int lenA =1;
    int lenB =1;
    while(tailA->next)
    {
        tailA=tailA->next;
        lenA++;
    }
    while(tailB->next)
    {
        tailB=tailB->next;
        lenB++;
    }
    if(tailA!=tailB)
    {
        return NULL;//说明不存在相交节点
    }
    //下面是存在相交节点并且求相交节点过程
    int gap = abs(lenA-lenB);
    struct ListNode* longList=headA;
    struct ListNode* shortList=headB;
    if(lenA<lenB)
    {
        longList=headB;
        shortList=headA;
    }
    while(gap--)
    {
        longList=longList->next;
    }
    while(longList!=shortList)
    {
        longList=longList->next;
        shortList=shortList->next;
    }
    return longList;
    

}

环形链表I

链接: link
题目描述:
在这里插入图片描述
在这里插入图片描述
题目思路:
本题题目思路依然是快慢指针,快指针一次走两步,慢指针一次走一步。

情况1:链表中不存在环,奇数个节点,循环结束条件为fast->next = NULL
在这里插入图片描述
在这里插入图片描述
情况2:链表中不存在环,偶数的节点,循环结束条件为fast=NULL
在这里插入图片描述
在这里插入图片描述
情况3:链表中存在环,依然是slow指针走一步,fast指针走两步,但是什么情况才能证明链表当中存在环呢?这是一个追击问题,如果链表当中存在环,那么总会有一次,两个指针指向同一个地址,也就是说slow=fast。
大家可以画一下,下图就是追击之后两指针相遇的位置在这里插入图片描述

代码实现:

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

两个问题:
问题1:slow一次走一步fast 一次走两步,一定会相遇吗?答案是一定会。
fast先进环,slow后进环,fast进环后开始追击slow,slow走1步,fast走两步,他们之间的距离缩小1。假设此时fast和slow的距离为N
在这里插入图片描述
问题2:slow一次走一步fast 一次走三步,一定会相遇吗?答案是不一定会。
fast先进环,slow后进环,fast进环后开始追击slow,slow走1步,fast走3步,他们之间的距离缩小2。
这时是否能追击到取决于fast和slow之间的距离N。
在这里插入图片描述
在这里插入图片描述
在环内追击时,取决于环内节点的个数C,此时slow和fast的距离是C-1
在这里插入图片描述
如果C-1为偶数,那么某一时刻,一定会追上。
如果C-1为奇数,那么永远都追不上。

环形链表II

链接: link
题目描述:
在这里插入图片描述
在这里插入图片描述
题目思路:
方法1:快慢指针

方法一的主要思路就是:一个指针从相遇点开始走,一个指针从链表头开始走,他们会在入环的第一个节点相遇。
slow一次走一步,fast一次走两步
假设下图中meet指针指向的节点为fast和slow指针相遇的节点。
在这里插入图片描述
假设
从链表头到入环的第一个节点的长度为L
入环第一个节点到meet的长度为X
环的长度为C
在这里插入图片描述
那么到相遇点meet时
slow指针走过的路程为:L+X
fast指针走过的路程为:L+nC-X
fast一次走两步,slow一次走一步
所以2
(L+X)=L+nC-X,所以L=nC-X=(n-1)*C+C-X,仔细观察这个式子,就是本题开头所说的思路:一个指针从头开始走,一直指针从相遇的地方开始在走,他们会在入环的第一个节点相遇。

这里的疑问是:为什么fast指针走过的路程为:L+n*C-X,不是L+C-X
如果L的长度很大,而C的长度很小呢?下图显然不能得到入口点
在这里插入图片描述

这里举一个例子:假设L长度为10,C的长度为2,slow指针一次走一步,fast指针一次走两步,当fast进环时,slow的位置如下图:
在这里插入图片描述
这就是为什么fast走过的路程是L+n*C-X,在slow进到环内之前,fast要先在环内转n(n的值根据具体实际情况推算)圈。

注意:本题slow和fast一定会相遇,不存在slow进环后转了几圈,fast才追上,因为他们之间的距离每次缩小一,slow进环后,slow走一圈,fast都走两圈了,肯定追上了。
代码实现:

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

方法2:
在这里插入图片描述
代码实现:

struct ListNode *detectCycle(struct ListNode *head) 
{
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    int len1 = 1;
    int len2 = 1;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)//有环
        {
            struct ListNode* meet = slow;
            struct ListNode* meetnext = meet->next;
            meet->next = NULL;
            struct ListNode* head1 = head;
            struct ListNode* head2 = meetnext;
            struct ListNode* tail1 = head1;
            struct ListNode* tail2 = head2;
            while(tail1->next)
            {
                tail1 = tail1->next;
                len1++;
            }
            while(tail2->next)
            {
                tail2 = tail2->next;
                len2++;
            }
            int gap = abs(len1-len2);
            struct ListNode* longList = head1;
            struct ListNode* shortList = head2;
            if(len2>len1)
            {
                longList=head2;
                shortList = head1;
            }
            while(gap--)
            {
                longList = longList->next;
            }
            while(longList!=shortList)
            {
                longList = longList->next;
                shortList=shortList->next;
            }
            return longList;
        }
    }
    return NULL;
}

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

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

相关文章

8年资深测试总结,性能测试基础知识(大全)你的进阶之路...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试&#xf…

力扣sql中等篇练习(十七)

力扣sql中等篇练习(十七) 1 计算布尔表达式的值 1.1 题目内容 1.1.1 基本题目信息1 1.1.2 基本题目信息2 1.1.3 示例输入输出 a 示例输入 b 示例输出 1.2 示例sql语句 # 使用SELECT子句中的子查询查询到对应的值 SELECT t1.left_operand,t1.operator,t1.right_operand,cas…

Obsidian templater日记模板添加一个随机问题

Obsidian templater日记模板添加一个随机问题 简介 每天日记里写同样的东西&#xff0c;感觉有点无聊&#xff0c;想问自己一些问题&#xff0c;每天不同。 查到有插件random structural diary&#xff0c;我想要的功能就是这样&#xff0c;但是没懂这个插件怎么放进templat…

【Android入门到项目实战-- 9.3】—— 加速度传感器的详细使用教程

基础知识 加速度传感器可以返回x、y、z三轴的加速度数值&#xff0c;该数值受地心引力的影响。 将手机平放桌面上&#xff0c;x、y、z轴默认为9.81&#xff1b;手机向下z轴为-9.81。 将手机向左倾斜&#xff0c;x轴为正&#xff0c;向右倾斜&#xff0c;x为负&#xff1b; 将手…

Windows11安装hadoop-3.3.0

一、安装Java 1. 下载Java 进入下载页面Java Archive Downloads - Java SE 8 Java SE Development Kit 8u191中 选择适合操作系统的下载文件 在安装好的路径下&#xff0c;将Java目录复制到C:\根目录下&#xff0c;形成C:\Java\jdk1.8.0_191目录结构 2. 设置环境变量 二、…

Docker虚拟化概念

Docker虚拟化概念 1、虚拟化技术的概念 虚拟化技术主要是将物理资源转变为逻辑上可以管理的资源&#xff1b;用以打破物理资源结构之间的壁垒&#xff1b;让计算的原件运行在虚拟的基础之上&#xff1b;而不是直接运行在硬件设备资源上&#xff1b; 说白了就是硬件资源转变成…

大数据开会记录【NiFi数据集成、AllData数据中台管理系统、RuoYi】

今天上午和下午开了个小会&#xff0c;上午说了一下Nifi&#xff0c;下午具体说了一下nifi和ruoyi。 目录 上午 下午 上午 三个人开会。 上次说的挖掘平台&#xff0c;您这边是否有技术人员对nifi比较熟悉&#xff0c;并且能够将相关功能集成到数据中台系统中。 现在结构化的…

不收费的电脑数据恢复软件EasyRecovery16

EasyRecovery是一款操作安全、恢复性比较高的数据恢复工具&#xff0c;小伙伴们可以使用EasyRecovery恢复各种各样被删除的文件、视频、图片等。EasyRecovery还可以支持恢复被格式化的媒体文件&#xff0c;只是使用EasyRecovery恢复时时间较久。如果小伙伴们有误删除的文件需要…

【Qt 从入门到入土】上篇

【Qt 从入门到入土】下篇 一个非常好的学习 Qt 的视频 本文目录 1. Qt 概述1.1 什么是 Qt1.2 Qt 的发展史1.3 支持的平台1.4 Qt 的版本1.5 Qt 的优点1.6 成功案例 2. 创建 Qt 项目2.1 使用向导创建2.2 手动创建2.3 .pro文件2.4 一个最简单的 Qt 应用程序2.5 Qt 命名规范和常用…

【Java入门合集】第三章面向对象编程(下)

【Java入门合集】第三章面向对象编程&#xff08;下&#xff09; 博主&#xff1a;命运之光 专栏&#xff1a;JAVA入门 学习目标 理解面向对象三大主要特征&#xff1b; 掌握类与对象的区别与使用&#xff1b; 掌握类中构造方法以及构造方法重载的概念及使用&#xff1b; 掌握包…

已做过算法题总结

217、存在重复元素(easy) 输入&#xff1a;nums [1,2,3,1] 输出&#xff1a;true 输入&#xff1a;nums [1,2,3,4] 输出&#xff1a;false 输入&#xff1a;nums [1,1,1,3,3,4,3,2,4,2] 输出&#xff1a;true 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 &…

【2106. 摘水果】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 在一个无限的 x 坐标轴上&#xff0c;有许多水果分布在其中某些位置。给你一个二维整数数组 fruits &#xff0c;其中 fruits[i] [positioni, amounti] 表示共有 amounti 个水果放置在 positioni 上…

Android平台播放透明视频

Android平台播放透明视频 思路 设计一种特殊的视频&#xff0c;它的一半内容存储alpha信息&#xff0c;另一半内容存储rgb信息&#xff0c;接着通过OpenGL获取每个像素点的alpha值和rgb值进行混合&#xff0c;最后出来的画面就是带有透明效果的视频了。 可以上下的分&#xf…

【疯狂造轮子-iOS】JSON转Model系列之二

1. 前言 上一篇《【疯狂造轮子-iOS】JSON转Model系列之一》实现了一个简陋的JSON转Model的库&#xff0c;不过还存在很多问题。下面我会尝试一个个去解决。 2. 存在问题及解决思路 2.1 没有考虑JSON数据并不一定是NSDictionary类型 有时候JSON并不一定是NSDictionary类型&…

【医学影像数据处理】2D/3D patch的crop和merge操作汇总

在做3D分割任务中&#xff0c;多数的方法多采用整体缩放&#xff0c;或裁剪成一个个小的patch操作&#xff0c;这样做的一个主要原因是内存问题。 相较于整体缩放&#xff0c;采用裁剪成patch的方法&#xff0c;对于小目标会更加的鲁棒&#xff0c;这也是大多数3D分割任务中常…

Leetcode448. 找到所有数组中消失的数字

Every day a leetcode 题目来源&#xff1a;448. 找到所有数组中消失的数字 解法1&#xff1a;STL set set 是一个集合类型的容器&#xff0c;里面的元素具有唯一性&#xff0c;并且所有元素都会根据元素的键值自动被排序&#xff0c;以红黑树为底层数据结构。 我们使用集合…

git上传大大大文件项目好折磨人

本来想把unity项目的源码上传上gitee啊&#xff0c;但是那个项目有1个多G&#xff0c;还是个半成品&#xff0c;要是写完&#xff0c;都不知道行不行 正常的上传 所用到的命令&#xff1a; 1、 git init 初始化&#xff0c;创建本地仓库 2、 git add . 添加到本地仓库 3、 git…

【C++】打开C++大门,踏入C++世界

文章目录 ☑️前言一. 浅看【C】关键字二. 命名空间1. 命名空间的定义&#x1f44c;2. 命名空间的使用&#x1f44c; 三. 【C】输入输出(IO)四. 缺省参数1. 缺省参数的概念&#x1f3c6;2. 缺省参数的分类&#x1f3c6; 五. 函数重载1. 函数重载的概念✌️2. 【C】支持函数重载…

【计算机专业漫谈】【计算机系统基础学习笔记】W2-2-2 模运算系统和补码表示

利用空档期时间学习一下计算机系统基础&#xff0c;以前对这些知识只停留在应试层面&#xff0c;今天终于能详细理解一下了。参考课程为南京大学袁春风老师的计算机系统基础MOOC&#xff0c;参考书籍也是袁老师的教材&#xff0c;这是我的听课自查资料整理后的笔记 补码表示法…

实验9 分类问题

1. 实验目的 ①掌握逻辑回归的基本原理&#xff0c;实现分类器&#xff0c;完成多分类任务&#xff1b; ②掌握逻辑回归中的平方损失函数、交叉熵损失函数以及平均交叉熵损失函数。 2. 实验内容 ①能够使用TensorFlow计算Sigmoid函数、准确率、交叉熵损失函数等&#xff0c;…