leetcode精选算法刷题训练篇 之 链表OJ(包含题目链接以及详细讲解)

在这里插入图片描述
好好学习,giao哥给你补🥚

1、移除链表元素

难度等级:⭐
题目链接:移除链表元素

2、链表的中间节点

难度等级:⭐⭐
题目链接:链表的中间节点

3、反转链表

难度等级:⭐⭐⭐
题目链接:反转链表

4、合并两个有序链表

难度等级:⭐⭐⭐⭐
题目链接:合并两个有序链表

5、分割链表

难度等级:⭐⭐⭐⭐⭐
题目链接:分割链表

6、环形链表的约瑟夫问题

难度等级:⭐⭐⭐⭐⭐⭐
题目链接:环形链表的约瑟夫问题

注:难度等级设置只是相对而言,仅供参考
–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–

1、移除链表元素

题目链接:移除链表元素
题目:
在这里插入图片描述解题思路: 定义一个新链表,遍历原链表找到不为val的节点,尾插在新链表当中。
解题代码:

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

struct ListNode* removeElements(struct ListNode* head, int val) {
    ListNode* newTail,*newHead;
    newTail = newHead = NULL;
    ListNode* pcur = head;
    while(pcur)
    {
        if(pcur->val != val)
        {
           if(newHead == NULL)
           {
               newHead = newTail = pcur;
           }
           else
           {
               newTail->next = pcur;
               newTail = newTail->next;
           }
        }
        pcur = pcur->next;   
    }
    if(newTail)
    {
        newTail->next = NULL;
    }
    return newHead;
}

该题为接口性问题,我们只要知道单链表结构体类型,知道如何来解题即可。

代码讲解:
第一步我们需要创建两个结构体指针,分别用来标记新链表的头(newHead)和尾(newTail),对于所传过来的形参head保险起见一般是不能直接改他的值的,所以我们创建结构体变量pcur来代替head进行链表的遍历。
这里先强调一下只要进入while循环,那么就说明原链表不为空链表,之后就可以判定当pcur所指的节点val不等于所给的val时就要进行尾插,同时我们还需要考虑所创建的新链表是否为空,也就是是否已经插入了节点,因为当第一次向新链表插入节点时我们的头指针newHead和尾指针newTail都需要指向该节点,而之后如果继续插入的话只需要移动尾指针newTail即可,所以我们是需要考虑新链表是否为空的情况。
那么如果pcur所指的节点val等于所给的val时我们直接将pcur向前面的节点移动即可(pcur = pcur->next)。
完成上面操作后,要让大家自己写的话可能有人会直接返回头节点的指针就结束了,但这是不对的
在这里插入图片描述我们就拿上面的图为例,val = 6,那么当pcur移动到第7个节点(最后一个节点)的时候我们按照上面所讲的逻辑就会把第7个节点进行删除,但是第6个节点的next里面还存着第7个节点的地址,所以我们还需要把第6个节点的next改成指向NULL,也就是代码中的if(newTail),判断newTail是否为空,因为上面我们也提到过**“只要进入while循环,那么就说明原链表不为空链表”**,那么只要出了while循环就说明pcur已经是空指针了,而如果newTail不为空,就说新链表里面已经“存有”节点了,那么直接newTail->next = NULL就完成将最后节点的指向改为空指针了而当newTail为空的时候,就说明原链表也是空链表。最后直接返回newHead即可。

2、链表的中间节点

题目链接:链表的中间节点
题目:
在这里插入图片描述解题思路: 快慢指针法
解题代码:

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

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

代码讲解:
所谓快慢指针法就是创建两个结构体指针变量slow和fast,然后让fast每次向前移动两个节点,让slow每次向前移动一个节点,最后如果链表的节点总数为奇数
在这里插入图片描述那么当fast->next为空指针的时候,这是slow便指向的是中间节点的位置
当链表节点为偶数的时候:
在这里插入图片描述这时当slow指到中间节点时fast指向的是空指针
所以我们while循环的判断条件为fast && fast->next,注意顺序不可以变,必须先先判断fast是否为空,如果为空那么该判定直接为假,后面fast->next就不会被判断,而如果把fast->next放在前面,当链表为奇数的时候,最后fast指向的是空指针,空指针也不会有next,并且编译也会报错。
这题我们就不需要再考虑传过来的head指针是否为空了,因为如果传过来空指针那么就不会进行while循环,直接将slow空指针进行了返回。

3、反转链表

题目链接:反转链表
题目:
在这里插入图片描述**解题思路:**创建三个结构体指针变量改变原链表每个节点所指的方向
解题代码:

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

typedef struct ListNode ListNode; 

struct ListNode* reverseList(struct ListNode* head) {
   ListNode* n1,*n2,*n3;
   n1 = NULL;
   n2 = head;
   if(head != NULL)
   {
      n3 = head->next;
   }

   while(n2)
   {
    n2->next = n1;
    n1 = n2;
    n2 = n3;
    if(n3 != NULL)
    {
        n3 = n3->next;
    }
   }
   return n1;
}

代码讲解:
我们创建三个结构体指针变量
在这里插入图片描述当链表节点大于2个的时候,三个指针分别指向图示位置,这里n1指的是空指针NULL,然后将n2所指向的下一个节点(n2->next),改变方向指向n1,再将n1向前移(n1 = n2),n2也向前移(n2 = n3),n3也向前移(n3 = n3->next)那么链表就会变成:
在这里插入图片描述while循环重复上面所述步骤,那么最后链表将变成:
在这里插入图片描述当n2为空时,链表的顺序将完全反转,所以while循环判断条件为n2。
while循环中为什么会有一个if判断?
上图中可以看出来n3先指向空指针,但此时结果并不符合我们的预期,需要再经过一次while循环,这时n2也将指向空指针,但是因为n3已经是空指针了,代码中n3 = n3->next就是错误的,这时候我们就不需要再将n3向前移动了,所以我们再n3 = n3->next代码前加上了一个if判断。
对于代码开始判断head是否为空也是同样的道理。

4、合并两个有序链表

题目链接:合并两个有序链表
题目:
在这里插入图片描述解题思路: 创建新链表,判断两个原链表节点大小,进行尾插

解题代码:

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

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    ListNode* slow,*fast;
    slow = fast = NULL;

    ListNode* n1 = list1;
    ListNode* n2 = list2;

    if(n1 == NULL)
    {
       return n2;
    }
    if(n2 == NULL)
    {
        return n1;
    }

    while(n1 && n2)
    {
        if(n1->val >= n2->val)
        {
            if(fast == NULL)
            {
                slow = fast = n2;
            }
            else
            {
                fast->next = n2;
                fast = n2;
            }
             n2 = n2->next;
        }
        else
        {
            if(fast == NULL)
            {
                slow = fast = n1;
            }
            else
            {
                fast->next = n1;
                fast = n1;
            }
            n1 = n1->next;
        }
    }

    if(n1)
    {
        fast->next = n1;
    }
    if(n2)
    {
        fast->next = n2;
    }
    return slow;
}

代码讲解:
因为有可能传过来空链表,所以我们需要考虑空链表的问题:

1.list1为空list2不为空
2.list2为空list1不为空
3.list1和list2都为空

当为上面所述状况时,我们开头的代码,两个if判断即可解决这三种情况。
那么只要是到whille循环的都不是空链表
之后我们就开始进行链表1和链表2每个节点的val值大小判断,并将小的节点尾插进新链表里面
这里还需要判断尾插时,所创建的新链表是否为空,因为空链表的尾插不同于不为空链表的尾插。
跳出while循环,指针n1和指针n2一定会有一个为空指针,另一个还指向链表,直接将还在指向链表的指针尾插进新链表里即可。

5、分割链表

题目链接:分割链表
题目:
在这里插入图片描述解题思路: 创建两个新链表,分别存放大于等于val的节点和小于val的节点,最后在将两个链表连接。
解题代码:

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

struct ListNode* partition(struct ListNode* head, int x){
    if(head == NULL)
    {
        return head;
    }

    ListNode* lessHead,*lessTail;
    lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
    ListNode* greaterHead,*greaterTail;
    greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));

    ListNode* pcur = head;
    while(pcur)
    {
        if(pcur->val < x)
        {
            lessTail->next = pcur;
            lessTail = pcur;
        }
        else
        {
            greaterTail->next = pcur;
            greaterTail = pcur;
        }
        pcur = pcur->next;
    }

    greaterTail->next = NULL;
    lessTail->next = greaterHead->next;
    
    ListNode* ret = lessHead->next;
    free(greaterHead);
    free(lessHead);
    return ret;
}

代码讲解:
这题需要注意的就是在最后我们需要将大链表(大于等于val的链表)的最后节点的next置为空指针即:greaterTail->next = NULL,不然代码可能会出现死循环。lessTail->next = greaterHead->next,完成了大链表与小链表的链接。最后将没有使用上的空间进行销毁

6、环形链表的约瑟夫问题

题目链接:环形链表的约瑟夫问题
题目:
在这里插入图片描述解题思路: 先创建循环链表,然后通过计数器进行节点的删除
解题代码:

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param n int整型 
 * @param m int整型 
 * @return int整型
 */
typedef struct ListNode ListNode;

ListNode* buyNode(int x)
{
    ListNode* newNode = (LisbuyNodetNode*)malloc(sizeof(ListNode));
    if(newNode == NULL)
    {
        exit(1);
    }
    newNode->val = x;
    newNode->next = NULL;

    return newNode;
}

ListNode* cresteList(int n)
{
    ListNode* phead = buyNode(1);
    ListNode* pTail = phead;
    for(int i=2; i<=n; i++)
    {
        pTail->next = buyNode(i);
        pTail = pTail->next;
    }
    pTail->next = phead;
    return phead;
}

int ysf(int n, int m ) {
    // write code here
    ListNode* pcur = cresteList(n);
    ListNode* prev = NULL;
    int count = 1;
    while(pcur != pcur->next)
    {
        if(count != m)
        {
            prev = pcur;
            pcur = pcur->next;
            count++;
        }
        else
        {
            prev->next = pcur->next;
            free(pcur);
            pcur = prev->next;
            count = 1;
        }
    }
    return pcur->val;
}

代码讲解:
首先我们要创建一个循环链表,通过cresteList和buyNode函数即可完成。
在这里插入图片描述我们假设m为2,n为5
那么实际画图如上面所示,开始pcur指向节点1,然后pcur向后移一次,同时将prev指向pcur的位置,此时计数器count要加加,那么count就等于m,要进行节点的删除,可以看上面解题代码,执行删除的操作时我们还需要将删除节点的前后节点进行连接,prev->next = pcur->next;执行的就是连接操作,然后释放掉节点pcur后要将pcur指向删除节点的下一个节点,也就是pcur = prev->next;注意,此时prev已经和第三个节点连接,所以prev->next指向的就是删除节点的下一个节点。
以此循环上面步骤,最后剩下的节点会自己指向自己,那么就将跳出while循环,返回对应val指即可。

完结撒❀

如果以上内容对你有帮助不妨点赞支持一下,以后还会分享更多编程知识,我们一起进步。
最后我想讲的是,据说点赞的都能找到漂亮女朋友
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#版开源免费的Bouncy Castle密码库

前言 今天大姚给大家分享一款C#版开源、免费的Bouncy Castle密码库&#xff1a;BouncyCastle。 项目介绍 BouncyCastle是一款C#版开源、免费的Bouncy Castle密码库&#xff0c;开发人员可以通过该项目在他们的 C# 应用程序中使用 Bouncy Castle 提供的各种密码学功能&#x…

git提交代码描述时如何换行(更新时间24/3/12)

问题复现&#xff08;信心满满使用转义字符换行&#xff09; 解决方法&#xff1a; 写多个-m字符串的结构可以实现自动换行 注意空格 git commit -m"第一行描述" -m"第二行描述" 效果演示&#xff1a;&#xff08;强迫症福利&#xff09;

近700所高校,2024年预算出炉!

办学经费&#xff0c;是高校发展的核心与基石。学校人才培养、科学研究等各项事业的开展&#xff0c;都有赖于教育经费的支持。 近日&#xff0c;全国已有北京、上海、江苏、浙江等20多个省&#xff08;市、自治区&#xff09;的高校对外公布了2024年预算经费&#xff0c;小编…

L2-035 完全二叉树的层序遍历(Python)

L2-035 完全二叉树的层序遍历 分数 25 全屏浏览 切换布局 作者 陈越 单位 浙江大学 一个二叉树&#xff0c;如果每一个层的结点数都达到最大值&#xff0c;则这个二叉树就是完美二叉树。对于深度为 D 的&#xff0c;有 N 个结点的二叉树&#xff0c;若其结点对应于相同深度…

深入联合文件系统

Union File System&#xff08;联合文件系统&#xff0c;UnionFS&#xff09;是一种轻量级的高性能分层文件系统&#xff0c;它支持将文件系统中的修改信息作为一次提交&#xff0c;并层层叠加&#xff0c;同时可以将不同目录挂载到同一个虚拟文件系统下&#xff0c;应用看到的…

C# 8.0+版本项目 string不可为空

1.在某一次新建项目的时候发现&#xff0c;新建的项目&#xff0c;写的测试接口&#xff0c;接口的入参有string的参数&#xff0c; 但是调用接口的时候string的参数没有传报了400&#xff0c;很奇怪&#xff0c;也没有语法错误之类的。 2.解决办法 在项目上右键->属性->…

计算机毕业设计-springboot+vue前后端分离电竞社交平台管理系统部分成果分享

4.5系统结构设计 本系统使用的角色主要有系统管理员、顾客、接单员&#xff0c;本系统为后台管理系统&#xff0c;游客用户可以经过账号注册&#xff0c;管理员审核通过后&#xff0c;用账号密码登录系统&#xff0c;查看后台首页&#xff0c;模块管理&#xff08;顾客信息&am…

Covalent Network (CQT) 通过统一 API 集成,为 Gnosis Chain 的 AI 潜力赋能

作为一个为超 225 个链提供服务的领先多链索引器&#xff0c;Covalent Network (CQT) 正在与知名的 EVM 区块链基础设施提供者 Gnosis Chain 展开一项激动人心的合作。这一战略合作象征着先进的实时数据索引技术的集成&#xff0c;包括 Covalent Network (CQT) 的统一 API 和 G…

前端入职配置新电脑!!!

前端岗位入职第一天到底应该做些什么呢&#xff1f;又该怎样高效的认识、融入团队&#xff1f;并快速进入工作状态呢&#xff1f;这篇文章就来分享一下&#xff0c;希望对即将走向或初入前端职场的你&#xff0c;能够有所帮助。内含大量链接&#xff0c;欢迎点赞收藏&#xff0…

解决gpt无法发送对话的问题

问题描述 如图&#xff0c;今天登上去发现怎么无法发送消息 解决 可能是cookie问题&#xff0c;重新删除了就行了 cookie删除后&#xff0c;需要重新登录&#xff0c;主题色也重置为原来的白色了

MQTT Topic通配符

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

简单了解一下Linux的文件系统和目录结构

前言 这篇技术文章简单探讨了Linux的文件系统和目录结构&#xff0c;通过详细介绍Linux文件系统的组织方式和各个目录的作用&#xff0c;读者将能够更好地理解Linux系统的运作机制&#xff0c;从而提升对系统管理和优化的能力。无论您是初学者还是有经验的Linux用户&#xff0…

100元就不能投资吗?不可能,WeTrade1招激活

100元就不能投资吗?当然能进行投资了&#xff0c;尤其是现在投资方式多样化&#xff0c;又灵活&#xff0c;简单来说放在支付宝中就行&#xff0c;但是在可以承担风险的前提下想获得更获得更多的收益&#xff0c;WeTrade认为可以通过杠杆实现这个目的。 如果用1:1的杠杆交易&…

【Python爬虫神器揭秘】手把手教你安装配置Scrapy,高效抓取网络数据

1、 引言 在大数据时代&#xff0c;网络上的信息犹如海洋般浩瀚。想要在这片海洋里挖掘宝藏&#xff0c;一款强大的工具必不可少。今天我们要带大家深入探索的就是Python界鼎鼎大名的爬虫框架——Scrapy。无论你是数据分析师、研究员还是开发者&#xff0c;学会利用Scrapy来自…

郑州大学2024年3月招新赛题解

1.两重二for循环维护次大值 这里我就直接用map维护了&#xff0c;多了个logn复杂度还是可以的&#xff0c;下面是AC代码&#xff1a; #include<bits/stdc.h> using namespace std; int n,a[1010]; map<int,int> mp; int main(){cin>>n;int sum0;map<int,…

惬意了解 —— 前端发展史

下拉底部&#xff0c;参与投票&#xff5e;&#xff5e; 前端发展史&#xff1a;从洪荒时代到现代 前端开发已经走过了将近20年的历程&#xff0c;从最早的纯静态页面到如今的现代前端框架&#xff0c;我们见证了前端技术的蓬勃发展。让我们一起回顾这段历史。 洪荒时代&…

git push解决办法:! [remote rejected] prod -> prod (pre-receive hook declined)

今天想把最近改的东西上传到Gogs上发版一下子的&#xff0c;但是发现有冲突合并不了&#xff0c;于是我切回自己的分支合并了prod&#xff0c;把冲突处理了一下子&#xff0c;还又增加了一点修改&#xff0c;push后.......又回到prod进行git push&#xff0c;哦豁~这就出了问题…

基于Springboot影城管理系统设计与实现

** &#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;** 一、研究背景…

【实战项目】Boost搜索引擎项目

目录 1. 项目的相关背景 2. 搜索引擎的相关宏观原理 3. 搜索引擎技术栈和项目环境 4. 正排索引 vs 倒排索引 - 搜索引擎具体原理 4.1 正排索引 4.2 目标文档进行分词 4.3 倒排索引 4.4 模拟一次查找的过程&#xff1a; 5. 编写数据去标签与数据清洗的模块 Parser 5.1…

[Linux][VM虚拟机]另外一台主机连自己主机的VM虚拟机

今天从工作室休息完回寝室&#xff0c;因为这个学期在学OS &#xff0c;一同学在弄VM装的CentOS&#xff0c;然后他就遇到了个问题&#xff0c;我顺便就去看了一下&#xff0c;帮着解决了一手&#xff0c;因为之前我也没遇到过这个问题&#xff0c;所以小小的记录一手。 问题背…