【数据结构】11道LeetCode链表OJ练习

news2024/11/24 1:45:29

文章目录

  • 1. 移除链表元素
  • 2. 反转链表
  • 3. 链表的中间节点
  • 4. 链表中倒数第k个节点
  • 5. 合并两个有序链表
  • 6. 链表分割
  • 7. 链表的回文结构
  • 8. 相交链表
  • 9. 环形链表
  • 10. 环形链表II
  • 11. 复制带随机指针的链表
  • 补充内容:浅谈顺序表和链表的区别


1. 移除链表元素

在这里插入图片描述 移除链表元素OJ链接

💝 思路:

我们可以重新定义一个申请一个新的虚拟头节点,该头节点不存储有效数据,然后我们遍历这个链表,找出数据不等于val的节点一一尾插在新的头节点之后,最后返回虚拟头节点的下一个节点即可。

💖 代码实现:

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode*newHead=(struct ListNode*)malloc(sizeof(struct ListNode));
    newHead->next=NULL;
    struct ListNode*tail=newHead;
    struct ListNode*cur=head;
    while(cur)
    {
        if(cur->val!=val)
        {
            tail->next=cur;
            tail=cur;
        }
        cur=cur->next;
    }
    tail->next=NULL;
    return newHead->next;
}

在这里插入图片描述


2. 反转链表

在这里插入图片描述
反转链表OJ链接

💝 思路:

要实现链表的反转,我们可以把头节点之后的节点依次头插到头节点之前即可以设置三个指针,依次迭代就可以完成。
在这里插入图片描述
💖 代码实现:

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

在这里插入图片描述


3. 链表的中间节点

在这里插入图片描述
链表的中间节点OJ链接

💝 思路:

这道题的最优解法是快慢指针,先定义一个快指针和慢指针都指向链表的头节点,快指针次一次走两步慢指针一次走一步。如果链表节点个数为奇数,则快指针的next为空时停止循环,此时慢指针指向的节点恰好为链表的中间节点。如果节点个数为偶数,则快指针为空时停止循环,此时的慢指针的指向也恰好为链表中间节点的第二个节点。
在这里插入图片描述
在这里插入图片描述
💖 代码实现:

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

在这里插入图片描述


4. 链表中倒数第k个节点

在这里插入图片描述
链表中倒数第K个节点OJ链接

💝 思路:

这道题的思路还是快慢指针,和上一个题不一样的是这个题运用到的思路不是快指针比满指针一次走的步数不同,而是先让快指针先走K步,然后慢指针和快指针一起走,当快指针指向空时,此时的慢指针的指向即为倒数第K个节点。这里需要注意的是如果K的值大于链表的长度,在快指针先走的时候就会指向0,这时候链表没有倒数第K个节点,需要返回一个空指针。

💖 代码实现:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    // write code here
    if(!pListHead)
        return NULL;
   struct ListNode*fast,*slow;
   fast=slow=pListHead;
   while(k--)
    {
        if(fast==NULL)
            return NULL;
        fast=fast->next;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }
    return slow;
}

在这里插入图片描述


5. 合并两个有序链表

在这里插入图片描述
合并两个有序链表OJ链接

💝 思路:

这个题的思路还是双指针,先定义一个虚拟头节点,防止后面需要判空的一系列麻烦操作,同时为了能够找到新的链表的尾节点,我们还需要定义一个尾节点方便尾插,从两个链表的头节点开始比较如果list1的节点数据小于list2,则将该节点尾插到虚拟头节点的后面,同时尾节点指向新的尾,如果其中一个链表为空,则停止循环,同时将不为空的链表链接到新的链表后面,最后返回新链表的头节点的下一个节点即可。
在这里插入图片描述
💖 代码实现:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode*virhead=(struct ListNode*)malloc(sizeof(struct ListNode));
    virhead->next=NULL;
    struct ListNode*tail=virhead;
    while(list1&&list2)
    {
        if(list1->val<list2->val)
        {
            tail->next=list1;
            tail=tail->next;
            list1=list1->next;
        }
        else
        {
            tail->next=list2;
            tail=tail->next;
            list2=list2->next;
        }
    }
    if(!list1) tail->next=list2;
    if(!list2) tail->next=list1;
    return virhead->next;
}

在这里插入图片描述


6. 链表分割

在这里插入图片描述
链表分割OJ链接

💝 思路:

要解这个题,我们的思路是:先创建两个带虚拟头节点的空链表greaterHead 和 lessHead,然后遍历题目所给我们的链表,遇到小于x的结点,尾插到lessHead链表的后面,否则的话尾插到greaterHead链表的后面。最后将两个新的链表按照lessHead->greaterHead 的顺序链接起来。最后再将此链表返回即可。在这里我们要注意的是greaterHead链表尾指针的next需要置空一下防止链表成环进入死循环。
在这里插入图片描述

💖 代码实现:

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
        struct ListNode*greaterHead,*greaterTail,*lessHead,*lessTail;
        greaterHead=greaterTail=(struct ListNode*)malloc(sizeof(struct ListNode));
        lessHead=lessTail=(struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode*cur=pHead;
        while(cur)
        {
            if(cur->val<x)
            {
                lessTail->next=cur;
                lessTail=lessTail->next;
            }
            else
            {
                greaterTail->next=cur;
                greaterTail=greaterTail->next;
            }
            cur=cur->next;
        }
        greaterTail->next=NULL;
        lessTail->next=greaterHead->next;
        pHead=lessHead->next;
        return pHead;
    }
};

在这里插入图片描述


7. 链表的回文结构

在这里插入图片描述
链表的回文结构OJ链接

💝 思路:

要判断链表是不是回文结构,我们可以先把链表的中间结点找出,然后将中间结点后面的结点逆置,最后再将前半部分的结点和逆置了的后半部分节点一一对比,如果都相等,说明该链表是回文结构。我们在前两个题里已经实现过寻找链表的中间结点和逆置链表这两个OJ题目,这里我们只需要复用前面写过的代码即可,我们还需要注意节点个数为奇数和偶数分别应该注意的地方。
在这里插入图片描述
💖 代码实现:

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode*fast=head;
    struct ListNode*slow=head;
    while(fast!=NULL&&fast->next!=NULL)
    {
        fast=fast->next->next;
        slow=slow->next;
    }
    return slow;
}
struct ListNode* reverseList(struct ListNode* head){
    struct ListNode*cur=head;
    struct ListNode*rhead=NULL;
    while(cur)
    {
        struct ListNode*next=cur->next;
        cur->next=rhead;
        rhead=cur;
        cur=next;
    }
    return rhead;
}
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        // write code here
        struct ListNode*mid=middleNode(A);
        struct ListNode*rhead=reverseList(mid);
        while(A&&rhead)
        {
            if(A->val!=rhead->val)
                return false;
            A=A->next;
            rhead=rhead->next;
        }
        return true;
    }
};

在这里插入图片描述


8. 相交链表

在这里插入图片描述
相交链表OJ链接

💝 思路:

对于这道题目,我们最容易判断的就是两个链表是否相交,只需要将两个链表遍历找到他们的尾节点,如果二者的尾节点地址相同,则说明两个链表相交。其实要找他们相交的起始节点也不难:当我们判断出链表相交后,首相分别计算出两个链表的结点个数之差记为gap,然后让结点个数多的那个链表先走gap步,然后二者同时走,并且同时比较每个节点的地址是否相同,如果相同,则这个节点就是我们要找的结点。
在这里插入图片描述

💖 代码实现:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode*curA=headA,*curB=headB;
    int lenA=0,lenB=0;
    while(curA->next)
    {
        lenA++;
        curA=curA->next;
    }
    while(curB->next)
    {
        lenB++;
        curB=curB->next;
    }
    if(curA!=curB)
        return NULL;
    int gap=abs(lenA-lenB);
    struct ListNode*longList=headA,*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;
}

在这里插入图片描述


9. 环形链表

在这里插入图片描述
环形链表OJ链接

💝 思路:
这个题我们使用一种最优的解法,定义两个指针,fast和slow指针,快指针一次走两步,慢指针一次走一步,如果最后快指针或者快指针的next指向了空,那么就说明链表是不带环的,如果在循环的过程中,慢指针追上了快指针,则说明链表是带环的那么具体是什么意思呢?我们下面来分析一下:

在这里插入图片描述
💖 代码实现:

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

在这里插入图片描述


10. 环形链表II

在这里插入图片描述
环形链表IIOJ链接

💝 思路一:

在我们讲这道题之前,我们需要把上道题目证明一下,大家在看上道题目的解析时是否想到过这么个问题,为什么两个指针都进入环后快指针一次走两步,满指针一次走一步快指针可以追上慢指针,如果快指针一次走3步走4步可不可以呢?那样是不是快指针更容易追上慢指针呢?
在这里插入图片描述
在这里插入图片描述
那么题目要求我们找到环的入口点又该如何找呢?这里又得用到了数学中的证明过程——我们分别以大环小环的情况分别来证明一下
在这里插入图片描述
💝 思路二:
在这里插入图片描述

💖 代码实现(一):

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

💖 代码实现(二):

struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
     if (headA == NULL || headB == NULL)
     {
         return NULL;
     }
     struct ListNode* curA = headA, * curB = headB;
     int lenA = 1;
     //找尾节点
     while (curA->next)
     {
         curA = curA->next;
         ++lenA;
     }
     int lenB = 1;
     while (curB->next)
     {
         curB = curB->next;
         ++lenB;
     }
     if (curA != curB)
     {
         return NULL;
     }
     struct ListNode* longList = headA, * shortList = headB;
     if (lenA < lenB)
     {
         longList = headB;
         shortList = headA;
     }
     //长的链表先走差距步
     int gap = abs(lenA - lenB);
     while (gap--)
     {
         longList = longList->next;
     }
     //同时走找交点
     while (longList != shortList)
     {
         longList = longList->next;
         shortList = shortList->next;
     }
     return longList;
 }
 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;
             struct ListNode* next = meet->next;
             meet->next = NULL;
             struct ListNode* entryNode = getIntersectionNode(head, next);
             //恢复环
             meet->next = next;
             return entryNode;
         }
     }
     return NULL;
}

在这里插入图片描述


11. 复制带随机指针的链表

在这里插入图片描述
复制带随机指针的链表OJ链接

💝 思路:

这道题目我们可以分为三步来解:

1> 遍历一边这个链表的所有节点,将每一个结点拷贝一份链接到源节点的后面,以便我们去寻找源节点的random结点指向的结点。

在这里插入图片描述
2> 通过源节点的random找到源节点的random所指向的结点,该结点的next结点即为拷贝的每一个结点的random结点所要指向的结点。

在这里插入图片描述
3> 将源节点后面所拷贝的结点全部解下来,然后将其链接成一个新的链表,再将原链表恢复,这道题目就大功告成了。

在这里插入图片描述
💖 代码实现:

struct Node* copyRandomList(struct Node* head) {
    //将拷贝结点链接到源节点后面
    struct Node*cur,*Next;
    cur=head;
    while(cur)
    {
        struct Node*copy=(struct Node*)malloc(sizeof(struct Node));
        Next=cur->next;
        copy->val=cur->val;
        cur->next=copy;
        copy->next=Next;
        cur=Next;
    }
    //设置拷贝节点
    cur=head;
    while(cur)
    {
        struct Node*copy=cur->next;
        if(cur->random==NULL)
            copy->random=NULL;
        else
            copy->random=cur->random->next;
        
        cur=copy->next;
    }
    //解下拷贝的结点
    cur=head;
    struct Node*newHead=NULL;
    struct Node*newTail=newHead;
    while(cur)
    {
        struct Node*copy=cur->next;
        cur->next=copy->next;
        if(newHead==NULL){
            newHead=copy;
            newTail=newHead;
        }else{
            newTail->next=copy;
            newTail=newTail->next;
        }
        cur=cur->next;
    }
    return newHead;
}

在这里插入图片描述


补充内容:浅谈顺序表和链表的区别

💖 下面我们来浅浅看一下链表和顺序表的区别(这里的链表指的是带头双向循环链表)

在这里插入图片描述

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

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

相关文章

扫雷游戏优化详解——c语言实现

文章目录 一、扫雷游戏的简单认识与解释 二、扫雷游戏的代码及思路实现 一、扫雷游戏的思路 1、菜单打印 2、创建扫雷区 3、初始化雷区 4、打印雷区 5、布置雷区 6、排雷 三、扫雷游戏代码的整合 game.h game.c test.c 标题&#xff1a;猜数字小游戏 作者&#xff1a;Ggggg…

你适合考PMP还是软考?两者的区别是否清楚,分别能给你带来什么价值

PMP与软考之间有什么区别&#xff0c;应该考哪个更适合自己&#xff1f; 下面从9个方面给大家简单的介绍做一个对比&#xff0c;希望能帮上忙~ 软考和PMP哪个更适合自己&#xff1f; 01 考试介绍 PMP&#xff1a;PMP是项目管理专业人士资格认证&#xff0c;由美国项目管理协…

腾讯云相同配置8核16G的云服务器和轻量服务器该如何选择?

很多个人或者中小企业用户在选择云服务器的时候&#xff0c;已经确认配置的情况下&#xff0c;去选购的时候发现有出现了轻量应用服务器&#xff0c;那么轻量应用服务器和云服务器又有哪些区别&#xff0c;价格为啥又有那么大的差别&#xff0c;该如何选择呢&#xff1f; 从上边…

SSM框架整合详细教程

目录 1. 什么是SSM&#xff1f; 2. SSM整合的时候容器之间如何访问 3. SSM下面的开发步骤 4. SSM整合时候时容易混乱的知识点 1. 什么是SSM&#xff1f; SSM是对三个框架名字的简写&#xff0c;其中第一个S指的是SpringMVC,第二个S指的是Spring&#xff0c;第三个M指的是M…

项目搭建(七)爱心代码❤网站部署(静态网站)

爱心代码❤网站部署&#xff08;静态网站&#xff09;一、环境基础二、修改Tomcat启动配置三、放置静态网站四、启动Tomcat一、环境基础 如果你已经部署了Apache-Tomcat&#xff0c;恭喜你&#xff0c;你已经完成90%的部署工作 如果没有tomcat&#xff0c;那你先部署tomcat吧 …

4_单机优化(确定性算法,优化框架)

优化框架机器学习的优化框架正则化经验风险最小化优化算法的收敛速率假设条件凸函数定义强凸函数定义光滑函数定义优化算法的分类机器学习的优化框架 正则化经验风险最小化 有监督的机器学习问题&#xff1a; 假设输入输出数据 Sn{(xi,yi);i1,...,n}S_n \left\{(x_i, y_i);…

C++与C语言中的字符串

目录 1、关于c语言中的字符串 &#xff08;1&#xff09;c语言中字符串与字符指针 &#xff08;2&#xff09;字符串结尾 2、关于c中的字符串string &#xff08;1&#xff09;从本质上了解string &#xff08;2&#xff09;c中的字符串转换与关联 &#xff08;3&#x…

【MySQL入门指北】MySQL备份及恢复

MySQL备份及恢复 文章目录MySQL备份及恢复1.Percona 介绍2.安装Percona 需要的 MySQL 包3.安装percona-xtrabackup4.完全备份流程5.完全恢复流程6.增量备份流程7.差异备份8.差异恢复流程9.记录的导入和导出10.mysqldumpbinlog11.MySQL恢复数据12.二进制日志恢复13.误删除库的问…

基于51单片机的室内温度可燃气体检测报警系统Proteus仿真

资料编号&#xff1a;133 下面是相关功能视频演示&#xff1a; 133-基于51单片机的室内温度可燃气体检测报警系统Proteus仿真&#xff08;源码仿真全套资料&#xff09;功能介绍&#xff1a; 采用51单片机作为主控&#xff0c;LCD1602显示当前温度和可燃气体浓度&#xff0c;…

Netty源码阅读(1)之——客户端源码梗概

目录 准备 开始 NioSocketChannel 的初始化过程 指定 初始化 关于unsafe属性&#xff1a; 关于pipeline的初始化 小结 EventLoopGroup初始化 小结 channel的注册过程 handler的注册过程 客户端连接 总结 准备 源码阅读基于4.1.84.Final版本。从github下载netty项目…

WordPress设置浏览器切换标签网站动态标题

我们在逛别人网站的时候&#xff0c;经常看到&#xff0c;有些网站当我们离开该页面浏览其他页面的时候&#xff0c;离开的页面标题上会显示比如&#xff1a;“你别走吖 Σ(っ Д ;)っ”这样的字样&#xff0c;当我们点回来的时候页面上面的标题又变成了“你又回来啦&#xff0…

[附源码]计算机毕业设计JAVAjsp学生档案管理系统

[附源码]计算机毕业设计JAVAjsp学生档案管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM myb…

前端基础向--从项目入手封装公共组件

本文就从 “详情卡片” 业务组件的封装的几个阶段来说明我在编写公共组件的设计思路。 1. 阶段一&#xff1a;基础需求 假设我们现在有这样一个需求&#xff1a;需要满足显示产品的详细信息&#xff1b;需要可以根据不同分辨率适配不同的显示方式&#xff08;2列&#xff0c;…

【Linux】进程通信 | 管道

今天让我们来认识如何使用管道来进行进程间通信 文章目录1.何为管道&#xff1f;1.1 管道是进程间通信的一种方式1.2 进程通信1.3 管道分类2.匿名管道2.0 康康源码2.1 创建2.2 父子通信完整代码2.3 等待写入等待读取等待源码中的体现2.4 控制多个子进程2.5 命令行 |3.命名管道3…

linux无界面手敲命令笔记

0 Ubuntu相关命令简介 1. 文件及目录操作命令 pwd&#xff1a;显示用户当前所处的目录 ls&#xff1a;列出目录下的文件清单 cd&#xff1a;改变当前目录cd … 返回上一级目cd / 进入根目录不加参数或参数为“~”&#xff0c;默认切换到用户主目录 mkdir&#xff1a;建立目录 …

Ant Design表单之labelCol 和wrapperCol的实际开发笔记

目录 前言 一、labelCol和wrapperCol是什么 二、布局的栅格化 1.布局的栅格化系统的工作原理 三、栅格常用的属性 1.左右偏移 2.区块间隔 3.栅格排序 四、labelCol和wrapperCol的实际使用 总结 前言 主要是记录一下栅格布局的一些属性和labelCol、wrapperCol等。 一…

[附源码]java毕业设计毕业设计管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

国产AI绘画软件“数画”刷爆朋友圈,网友到底在画什么

人们常说&#xff0c;眼见为实&#xff0c;只有自己亲眼见到的才会相信。但是我们都知道眼睛会产生错觉&#xff0c;而且人们在生活中被错觉误导的情况屡见不鲜。例如图中&#xff0c;你以为她们肯定是真人的照片。世界上有些事情&#xff0c;即使是自己亲眼所见到的也未必一定…

c/c++内存管理

前言&#xff1a; 开篇前就聊聊篮球&#xff0c;在众多球星中&#xff0c;我觉得杜兰特&#xff08;KD&#xff09;非常专注于篮球&#xff0c;他一直坚持他所热爱的事业。尽管有很多缺点&#xff0c;但是他对于篮球的态度是坚定不移&#xff0c;这是我非常钦佩的。当然库里&am…

大数据环境搭建 —— VMware Workstation 安装详细教程

大数据系列文章&#xff1a;&#x1f449; 目录 &#x1f448; 文章目录一、下载安装包1. 下载 VMware Workstation2. 小技巧二、安装软件1. 软件安装2. 虚拟环境搭建一、下载安装包 1. 下载 VMware Workstation ① 打开 VMware Workstation 官方下载网站 VMware Workstati…