数据结构——单链表OJ题

news2024/9/20 18:37:23

在这里插入图片描述

单链表OJ题

  • 前言
  • 一、删除链表中等于给定值 val 的所有节点
  • 二、反转一个单链表
  • 三、返回链表的中间结点
  • 四、输出该链表中倒数第k个结点
  • 五、将两个有序链表合并
  • 六、链表的回文结构
  • 七、将链表分割成两部分
  • 八、找出第一个公共结点
  • 九、判断链表中是否有环
  • 总结


前言

在前面的博客中我们知道了什么是单链表以及如何建立单链表!
现在让我们来检验一下学习成果吧!

提示:此博客中题目均来自牛客网以及力扣网!在题目中我会附带两大网站的链接,大家也可以去练习一下!
若有链接问题可以在评论区及时反馈!


一、删除链表中等于给定值 val 的所有节点

题目链接:OJ链接
在这里插入图片描述

提示:
列表中的节点数目在范围 [0, 104] 内
1 <= Node.val <= 50
0 <= val <= 50

思路解析:
在这里插入图片描述

代码演示:

struct ListNode* removeElements(struct ListNode* head, int val) {
     struct ListNode* newhead = NULL;
     struct ListNode* move = head;
     struct ListNode* tail = NULL;

     while (move != NULL) {
         if (move->val != val) {
             if (tail == NULL) {//如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
                 newhead = tail = move;
                 move = move->next;
             }
             else {
                 tail->next = move;
                 move = move->next;
                 tail = tail->next;
             }
         }
         else {
             struct ListNode* temp = move;//新建结点保存要free的地址,以免free后造成节点丢失
             move = move->next;
             free(temp);
         }
     }
     if (tail)//如果新链表不为空,则将其尾结点的next置空
         tail->next = NULL;
     return newhead;
 }

二、反转一个单链表

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000

思路解析:
在这里插入图片描述

代码演示:

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* move1 = head;
    struct ListNode* tail = head;
    if (head == NULL || head->next == NULL) {//如果链表为空或者只有一个结点,则不需要反转
        return tail;
    }
    struct ListNode* move2 = move1->next;
    while (move2) {
        struct ListNode* temp = move2->next;//保存下一个结点的地址,防止后面的节点丢失
        move2->next = move1;
        move1 = move2;
        move2 = temp;
    }
    tail->next = NULL;//尾结点的next置空
    struct ListNode* newhead = move1;//move1最后指向了反转链表的起始结点
    return newhead;
}

三、返回链表的中间结点

题目链接:OJ链接
在这里插入图片描述

提示:
链表的结点数范围是 [1, 100]
1 <= Node.val <= 100

思路解析:
在这里插入图片描述

代码演示:

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode*move1=head;
    struct ListNode*move2=head;
    while(move2!=NULL&&move2->next!=NULL){//此处move2!=NULL和move2->next!=NULL
        move1=move1->next;                //的位置不能交换,否则会造成空指针错误
        move2=move2->next->next;
    }
    return move1;
}

四、输出该链表中倒数第k个结点

题目链接:OJ链接
在这里插入图片描述
思路解析:
在这里插入图片描述

代码演示:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    
    struct ListNode*move1=pListHead;
    struct ListNode*move2=pListHead;
    int i=k;
    while(i>0&&move2!=NULL){//move2向后移动k位
        move2=move2->next;
            i--;
    }
    if(move2==NULL&&i>0){//如果k大于链表结点数目,则返回NULL
        return move2;
    }
    while(move2){
        move1=move1->next;
        move2=move2->next;
    }
    return move1;
}

五、将两个有序链表合并

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列

思路解析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码演示:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    
    struct ListNode*move1=list1;
    struct ListNode*move2=list2;
    struct ListNode*newnode=NULL;
    struct ListNode*tail=NULL;
    while(move1!=NULL&&move2!=NULL){
        if(move1->val<=move2->val){
            if(tail==NULL){{//如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
            newnode=tail=move1;
            move1=move1->next;
            }
            else{
                tail->next=move1;
                move1=move1->next;
                tail=tail->next;
            }
        }
        else{
            if(tail==NULL){//如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
                newnode=tail=move2;
                move2=move2->next;
            }
            else{
                tail->next=move2;
                move2=move2->next;
                tail=tail->next;
            }
            }
    }
    if(move1==NULL){//如果链表1遍历完而链表2没有,则将链表2剩余结点尾插到newnode中
        while(move2!=NULL){
            if(tail==NULL){//如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
                newnode=tail=move2;
                move2=move2->next;
            }
            else{
                tail->next=move2;
                move2=move2->next;
                tail=tail->next;
            }
        }
    }
      if(move2==NULL){//如果链表2遍历完而链表1没有,则将链表1剩余结点尾插到newnode中
        while(move1!=NULL){
           if(tail==NULL){//如果newnode为NULL,则tail等于newnode,则直接将结点地址赋予tail
            newnode=tail=move1;
            move1=move1->next;
            }
            else{
                tail->next=move1;
                move1=move1->next;
                tail=tail->next;
            }
        }
    }
      return newnode;
}

六、链表的回文结构

题目链接:OJ链接

在这里插入图片描述
思路解析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码演示:

bool chkPalindrome(struct ListNode* A) {
    struct ListNode* move1 = A;
    struct ListNode* move2 = A;
    struct ListNode* move3 = A;
    struct ListNode* newnode = NULL;
    struct ListNode* tail = NULL;
    while (move2 != NULL&&move2->next != NULL ) {//找到中间节点
        move1 = move1->next;
        move2 = move2->next->next;
    }
    if (move2 == NULL);//如果节点个数为奇数,则move1向后移动一位
    else {
        move1 = move1->next;
    }
    while (move1 != NULL) {//将后半段链表头插到newnode中
        if (newnode == NULL) {
            newnode = tail = move1;
            move1 = move1->next;
            tail->next = NULL;
        }
        else {
            struct ListNode* temp = move1->next;
            move1->next = newnode;
            newnode = move1;
            move1 = temp;
        }
    }
    struct ListNode* cmp = newnode;
    while (move3 != NULL && cmp != NULL) {//比较原链表前半段和newnode是否相同
        if (move3->val != cmp->val) {
            return 0;
        }
        else {
            move3 = move3->next;
            cmp = cmp->next;
        }
    }
    return 1;
}

七、将链表分割成两部分

题目链接:OJ链接
在这里插入图片描述
思路解析:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

代码演示:

ListNode* partition(ListNode* pHead, int x) {
        struct ListNode*head1=(struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode*head2=(struct ListNode*)malloc(sizeof(struct ListNode));
        struct ListNode*tail1=head1;
        struct ListNode*tail2=head2;
        struct ListNode*move=pHead;
        while(move){
            if(move->val<x){
                tail1->next=move;
                move=move->next;
                tail1=tail1->next;
            }
            else{
                tail2->next=move;
                move=move->next;
                tail2=tail2->next;
            }
            }
        tail2->next=NULL;//将尾指针的next置空
        tail1->next=head2->next;
        struct ListNode*temp1=head1;
        struct ListNode*temp2=head2;
        head1=head1->next;//指针指向头结点的下一节点
        free(temp1);//释放掉创建的头结点
        free(temp2);
        return head1;
    }

八、找出第一个公共结点

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:
函数返回结果后,链表必须 保持其原始结构 。

思路解析:
在这里插入图片描述
在这里插入图片描述

代码演示:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode *move1=headA;
    struct ListNode *move2=headB;
    int len1=1,len2=1;
    while(move1){//得到链表A的长度
        move1=move1->next;
        len1++;
    }
    while(move2){//得到链表B的长度
        move2=move2->next;
        len2++;
    }
    int k=abs(len1-len2);//取相减的绝对值
    struct ListNode *moveA=headA;
    struct ListNode *moveB=headB;
    if(len1>len2){//较长的链表走k步
        while(k--){
            moveA=moveA->next;
        }
    }
      if(len1<len2){
        while(k--){
            moveB=moveB->next;
        }
    }
      while(moveA&&moveB){
        if(moveA==moveB)
            return moveA;//若地址相同则返回
        moveA=moveA->next;
        moveB=moveB->next;
    }
    return NULL;

九、判断链表中是否有环

题目链接:OJ链接
在这里插入图片描述
在这里插入图片描述

提示:

链表中节点的数目范围是 [0, 104]
-105 <= Node.val <= 105
pos 为 -1 或者链表中的一个 有效索引 。

思路解析:
在这里插入图片描述

代码演示:

bool hasCycle(struct ListNode *head) {
    struct ListNode*move1=head;
    struct ListNode*move2=head;
    while(move1&&move2&&move2->next){//此处move2和move2->next的顺序不可交换
        move1=move1->next;           //否则会导致空指针错误
        move2=move2->next->next;
        if(move1==move2)
            return true;
    }
    return false;
}

总结

这九道单链表OJ都是我见过的很经典的题型!
在这里为大家分享一下!
希望有更多的人能够通过这些题目更好地掌握单链表相关的知识!

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

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

相关文章

13-4_Qt 5.9 C++开发指南_基于QWaitCondition 的线程同步_Wait

在多线程的程序中&#xff0c;多个线程之间的同步实际上就是它们之间的协调问题。例如上一小节讲到的3个线程的例子中&#xff0c;假设 threadDAQ 写满一个缓冲区之后&#xff0c;threadShow 和 threadSaveFile 才能对缓冲区进行读操作。前面采用的互斥量和基于 OReadWriteLock…

【calc】需要使用新应用以打开此ms-calculator链接

问题出现 win10系统&#xff0c;winr输入calc调用计算器时候出现 需要使用新应用以打开此ms-calculator 链接 解决操作 左下角右键单击->Windows Powershell(管理员) # 先执行恢复商店 Get-AppXPackage *WindowsStore* -AllUsers | Foreach {Add-AppxPackage -Disable…

根据URL批量下载文件并压缩成zip文件

根据url批量下载图片或者视频&#xff0c;只需要将图片的url和名称放到数组对象即可&#xff0c;例如&#xff1a; let fileArr [{fvUrl:https://image.xuboren.com/image/2023/07/26/1410829074764cdbaa4314a084eb749e.jpg,fvName: 图片名称},{fvUrl:https://image.xuboren.…

雷柏VT350S反馈更敏捷,PC玩家不可或缺的游戏利器

FPS还有MOBA游戏是很多PC玩家的最爱道&#xff0c;一款好的鼠标可以让我们在游戏中更加得心应手&#xff0c;关键时刻甚至能逆转乾坤。以前&#xff0c;有线鼠标总是让人觉得不够自由&#xff0c;无线鼠标又担心延迟和续航。现在新款的无线鼠标终于能够做到超低延迟了&#xff…

uniapp 实现滑动元素并下方有滚动条显示

用uniapp实现下图的样式 代码如下&#xff1a; <template><view class"content"><view class"data-box" ref"dataBox" touchend"handleEnd"><view class"data-list"><view class"data-ite…

【黑马程序员前端】JavaScript入门到精通--20230801

B站链接 HTML相关知识【黑马程序员前端】 https://blog.csdn.net/m0_48964052/article/details/125951658 CSS相关知识【黑马程序员前端】 https://blog.csdn.net/m0_48964052/article/details/125951788 黑马程序员——JavaScript基础1&#xff08;初识 JavaScript&…

算法通关村第二关——反转链表白银笔记

文章目录 1.链表指定区间翻转2.两两交换链表中的节点 1.链表指定区间翻转 LeetCode 92.反转链表 解法一&#xff1a;头插法。利用虚拟节点进行反转&#xff0c;因为头节点有可能发生变化&#xff0c;比如 left1 那么需要 dummyNode.next 记录头结点&#xff0c;使用虚拟头节点…

【PostgreSQL】系列之 一 schema详解(二)

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

保留网络:大型语言模型的Transformer继任者

原文信息 原文题目&#xff1a;《Retentive Network: A Successor to Transformer for Large Language Models》 原文引用&#xff1a;Sun Y, Dong L, Huang S, et al. Retentive Network: A Successor to Transformer for Large Language Models[J]. arXiv preprint arXiv:2…

Java基础篇_1.3——数据类型和运算符

目录 1.表达式 1.1 Scanner输入流的介绍 1.2 常用运算符 附加逻辑运算符的短路与、短路或 2.位运算符 2.1 位运算的案例 1.表达式 1.1 Scanner输入流的介绍 导包 improt java.util.Scanner 创建Scanner对象 获取用户输入的数据 可以通过以下方法接受用户从键盘上输…

【JavaSE】初步认识类和对象

【本节目标】 1. 掌握类的定义方式以及对象的实例化 2. 掌握类中的成员变量和成员方法的使用 3. 掌握对象的整个初始化过程 目录 1. 面向对象的初步认知 2. 类定义和使用 3. 类的实例化 4. this引用 1. 面向对象的初步认知 1.1 什么是面向对象 Java是一门纯面向对象的语…

二次开发了个寂寞之HttpRunnerManager接口测试管理平台

文章目录 一、背景1、二次开发1.1、首页1.2、项目列表1.3、用例列表1.4、新增用例1.5、测试套件1.6、查看报告 二、总结 一、背景 自入职起&#xff0c;就在公司内部引入开源接口测试平台&#xff0c;选一个大家勉强看得懂源码的开源项目&#xff0c;方便后续的二次开发&#x…

Docker基础命令(二)

一、搜索镜像 1.在https://hub.docker.com/u/library 上搜索需要的镜像 2.查看需要的版本 3.下载指定版本 docker pull python:3.6 下载完成查看 docker images 问题&#xff1a;怎样用docker中的Python&#xff1f;&#xff1f;&#xff1f; 二、交互模式使用容器 1. 运行…

【mmdeploy】mmseg转ONNX/TensorRT

1.关于mmdeploy MMDeploy 是 OpenMMLab 模型部署工具箱&#xff0c;为各算法库提供统一的部署体验。基于 MMDeploy&#xff0c;开发者可以轻松从训练 repo 生成指定硬件所需 SDK&#xff0c;省去大量适配时间。MMDeploy 提供了一系列工具&#xff0c;帮助您更轻松的将 OpenMMLa…

前端Vue入门-day06-路由进阶

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 路由的封装抽离 声明式导航 导航链接 两个类名 自定义高亮类名 跳转传参 1. 查询参数传参 2. 动态…

Mysql-学习笔记

文章目录 1. 数据库1.1 Mysql安装及常用代码1.2 SQL介绍1.3 SQL分类1. DDL-操作数据库&#xff0c;表2. DML-对表中的数据进行增删改3. DQL-对表中的数据进行查询条件查询模糊查询排序查询分组查询分页查询 4. DCL-对数据库进行权限控制外键约束表关系-多对多多表查询事务 1. 数…

netty chinaread 不执行 的总结

netty chinaedred 不执行 目录概述需求&#xff1a; 设计思路实现思路分析1.netty chinaedred 拓展实现性能参数测试&#xff1a; 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness…

登月再进一步:Apollo自动驾驶的里程碑

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…