数据结构——单链表OJ题(上)

news2024/12/23 17:40:58

目录

一、移除链表元素

1.思路

2.注意

3.解题

二、反转链表

思路1:三指针翻转法

(1)注意

(2)解题

思路2:头插法

(1)注意

(2)解题

三、链表的中间结点

思路1:快慢指针法

(1)注意

(2)解题 

思路2:两次遍历法

(1)注意

(2)解题

四、返回倒数第k个结点

1.思路:快慢指针法

2.注意

3.解题

五、合并两个有序链表

1.思路

2.注意

3.解题

六、链表分割

1.思路

2.注意

3.解题

七、写在最后

 


一、移除链表元素

1.思路

创建一个新链表,用指针pcur遍历原链表,对每个结点的数据进行判断,如果等于val则不做处理,如果不相等则尾插到新链表中。

2.注意

(1)原链表可能为空,那么返回NULL;

(2)最后记得将newTail指向NULL,在此之前需要判断newTail不能为空,因为如果为空,不存在newTail->next。

3.解题

typedef struct ListNode ListNode;
struct ListNode*removeElements(ListNode* head , int val)
{
    if(head == NULL)//传入的该链表可能为空
    {
        return NULL;
    }
    //创建一个新链表
    ListNode* newHead = NULL;
    ListNode* newTail = NULL;
    //创建一个遍历该链表的指针
    ListNode* pcur = head;
    while(pcur)
    {
        if(pcur->val != val)
        {
            如果不等于val,尾插到新链表中
            if(newHead == NULL)
            {
                newHead = newTail = pcur;
            }
            else
            {
                newTail->next = pcur;
                newTail = newTail->next;
            }
        }
        pcur = pcur->next;
    }
    //将尾结点指向NULL
    if(newTail)
    {
        newTail->next = NULL;
    }
    return newHead;
}

二、反转链表

思路1:三指针翻转法

创建三个指针n1,n2,n3分别指向NULL、head和head->next,改变指向,将n2指向n1,进行循环遍历原链表。

(1)注意

①原链表可能为空,那么返回NULL;

②n1为反转链表的头结点。

(2)解题

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

思路2:头插法

创建新链表,通过pcur遍历原链表,将数据头插到原链表中,得到反转链表。

(1)注意

①创建新指针保存pcur的下一个结点,否则pcur无法找到原位置。

(2)解题

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head)
{
    //新链表
    ListNode* newhead = NULL;
    ListNode* pcur = head;
    while(pcur)
    {
        //保存当前结点的下一个结点
        ListNode* next = pcur->next;
        //头插新结点
        pcur->next = newhead;
        //更新头结点
        newhead = pcur;
        //移动到下一个结点
        pcur = next;
    }
    return newhead;
}

三、链表的中间结点

思路1:快慢指针法

初始时,快指针和慢指针都指向头结点。快指针一次经过两个结点,慢指针一次经过一个节点,当快指针走到链表结尾时,慢指针指向链表中间。

(1)注意

①分别分析一下链表长度为奇数和偶数时的情况(具体在代码中);

②最后返回指向链表中间的指针slow。

(2)解题 

typedef struct ListNode ListNode;
ListNode* middleNode(ListNode* head)
{
    ListNode* fast = head;
    ListNode* slow = head;
    while(fast && fast->next)
    //由于fast->next要取next,因此不能为空
    //且不能交换顺序:否则链表长度为偶数的情况不能实现
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

思路2:两次遍历法

第一次遍历得到链表的长度len,由此得到半个长度mid,第二次遍历得到中间结点。

(1)注意

①mid为len/2+1(len为int类型);

②在第二个while循环中,pcur初始为head,每进行一次循环pcur就指向下一个结点。因此,当mid写为len/2,那么在第二次循环中就顺利可实现。

(2)解题

typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) 
{
    ListNode* pcur = head;
    int len = 0;
    //遍历得到链表的长度len
    while(pcur)
    {
        len++;
        pcur = pcur->next;
    }
    int mid = len / 2 ;
    //让pcur遍历链表,得到中间结点
    pcur = head;
    while(mid--)
    {
        pcur = pcur->next;
    }
    return pcur;
}

四、返回倒数第k个结点

1.思路:快慢指针法

初始时,快指针和慢指针都指向头结点。快指针先走k步,然后快、慢指针同时走,当快指针走到链表末尾时,慢指针走到倒数第k个结点。

2.注意

①返回的是倒数第k个结点保存的数据,而非指针;

②若k大于链表长度,fast会为空,此时返回NULL。

3.解题

typedef struct ListNode ListNode;
int kthToLast(struct ListNode* head, int k)
{
    ListNode* fast = head;
    ListNode* slow = head;
    while(k--)
    {
        if(fast)
        {
            fast = fast->next;
        }
        else 
        {
            return NULL;
        }
    }
    while(fast)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow->val;
}

五、合并两个有序链表

1.思路

创建两个指针分别遍历两个链表,比较两个指针指向结点存储的数据,创建新链表,将小的数据存储在新链表中。

2.注意

①使用malloc创建非空链表,在尾插数据时不再需要判断newHead是否为NULL,避免代码冗余;

②当n1和n2其中一个为空会跳出循环,说明遍历完成。此时需要将另外一个尾插到新链表中。

③不必再令newTail指向空,因为此时尾结点不是newTail,而是后续尾插的n1或n2。

3.解题

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    if(list1 == NULL)
    {
        return list2;
    }
    if(list2 == NULL)
    {
        return list1;
    }
    //创建新链表
    ListNode* newHead, *newTail;
    newHead = newTail = (ListNode*)malloc(sizeof(ListNode));
    ListNode* n1 = list1;
    ListNode* n2 = list2;
    while(n1 && n2)
    {
        if(n1->val < n2->val)
        {
            newTail->next = n1;
            newTail = newTail->next;
            n1 = n1->next;
        }
        else
        {
            newTail->next = n2;
            newTail = newTail->next;
            n2 = n2->next;
        }
    }
    if(n1)
    {
        newTail->next = n1;
    }
    if(n2)
    {
        newTail->next = n2;
    }
    ListNode* ret = newHead->next;
    free(newHead);
    newHead = NULL;
    return ret;
}

六、链表分割

1.思路

创建两个新链表(大于x和小于x的分别存储在两个链表中),用pcur遍历原链表,最后将大链表尾插在小链表后。

2.注意

①使用malloc创建两个非空链表,分别存储大于和小于x的数据。

3.解题

typedef struct ListNode ListNode;
ListNode* partition(ListNode* pHead, int x) 
    {
        //大链表
        ListNode* greaterHead, *greaterTail;
        greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));
        //小链表
        ListNode* lessHead,*lessTail;
        lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
        ListNode* pcur = pHead;
        while(pcur)
        {
            if(pcur->val < x)
            {
                lessTail->next = pcur;
                lessTail = lessTail->next;
            }
            else 
            {
                greaterTail->next = pcur;
                greaterTail = greaterTail->next;
            }
            pcur = pcur->next;
        }
        lessTail->next = greaterHead->next;
        greaterTail->next = NULL;
        ListNode* ret = lessHead->next;
        free(lessHead);
        free(greaterHead);
        lessHead = greaterHead = NULL;
        return ret;
    }

七、写在最后

一起加油,敬请期待“单链表OJ题(下)”~

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

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

相关文章

depcheck 前端依赖检查

介绍 depcheck 是一款用于检测项目中 未使用依赖项 的工具。 depcheck 通过扫描项目文件&#xff0c;帮助你找出未被引用的依赖&#xff0c;从而优化项目。 优势&#xff1a; 简单易用: 仅需几个简单的命令&#xff0c;就能够扫描并列出未使用的依赖项&#xff0c;让你快速了…

The Schematic workflow failed. See above.

在使用 ng new 新建Angular项目的时候会报一个错误&#xff1a;The Schematic workflow failed. See above. 解决办法&#xff1a; 只需要在后面加上 --skip-install 参数&#xff0c;就不会报错了。 ng new myapp --skip-install

打工人电脑里都需要的远程控制软件有哪些?这4款不能错过

不巧前几天台风&#xff0c;实在没办法到公司&#xff0c;但是项目还得继续&#xff0c;这时候远程控制电脑的技巧可谓是帮了我大忙了。不知道平常的你偶尔会不会也需要远程控制电脑的操作&#xff0c;如果有就继续看下去吧。 1.向日魁远程控制 直通车>>https://down.o…

AJAX-Promise 详解

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 前言 一、Promise基本概念 1.1 定义 1.2 状态 1.3 构造函数 二、Promise基本用法 2.1 then() 2.2 ca…

ThinkPHP一对一关联模型的运用(ORM)

一、序言 最近在写ThinkPHP关联模型的时候一些用法总忘&#xff0c;我就想通过写博客的方式复习和整理下一些用法。 具体版本&#xff1a; topthink/framework&#xff1a;6.1.4topthink/think-orm&#xff1a;2.0.61 二、实例应用 1、一对一关联 1.1、我先设计了两张表&#x…

根据题意写出完整的css,html和js代码【购物车模块页面及功能实现】

🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 问题描述 根据题意写出完…

基于微信小程序+SpringBoot+Vue的社区超市管理系统(带1w+文档)

基于微信小程序SpringBootVue的社区超市管理系统(带1w文档) 基于微信小程序SpringBootVue的社区超市管理系统(带1w文档) 为了让商品信息的管理模式进行升级&#xff0c;也为了更好的维护商品信息&#xff0c;社区超市管理系统的开发运用就显得很有必要&#xff0c;因为它不仅可…

C# 植物大战僵尸

Winform 版本开发 高效率、流畅植物大战僵尸 git地址&#xff1a;冯腾飞/植物大战僵尸

go语言day19 使用git上传包文件到github Gin框架入门

git分布式版本控制系统_git切换head指针-CSDN博客 获取请求参数并和struct结构体绑定_哔哩哔哩_bilibili &#xff08;gin框架&#xff09; GO: 引入GIn框架_go 引入 gin-CSDN博客 使用git上传包文件 1&#xff09;创建一个github账户&#xff0c;进入Repositories个人仓…

我在百科荣创企业实践——简易函数信号发生器(6)

对于高职教师来说,必不可少的一个任务就是参加企业实践。这个暑假,本人也没闲着,报名参加了上海市电子信息类教师企业实践。7月8日到13日,有幸来到美丽的泉城济南,远离了上海的酷暑,走进了百科荣创科技发展有限公司。在这短短的一周时间里,我结合自己的教学经验和企业的…

buu做题(8)

[安洵杯 2019]easy_web 查看源代码可以发现一长串的base64编码 就是页面上的一张图片 回到原页面,url上面也有一些奇怪的参数 经过两次base64和一次hex 解密后得到 555.png 应该就是包含着页面上的这张图片 然后尝试将index.php 按照这样的方式编码, 看看能不能包含到 TmprMl…

后端解决跨域(Cross-Origin Resource Sharing)(三种方式)

注解CrossOrigin 控制层的类上或者方法上加注解CrossOrigin 实现接口并重写方法 Configuration public class CorsConfig implements WebMvcConfigurer {Overridepublic void addCorsMappings(CorsRegistry registry) {// 设置允许跨域的路径registry.addMapping("/**&qu…

算法通关:006_4二分查找:寻找数组中的峰值

文章目录 描述主要代码全部代码运行结果总结 二分法不一定只能用在有序数组中。 描述 leetcode&#xff1a;162 主要代码 //二分法查找峰值public static int findPeakElement(int[] arr){if (arr.length 1){//randomArray()不会出现arr null的情况return 0;}//先检查 0…

LabVIEW操作系列1

系列文章目录 我的记录&#xff1a; LabVIEW操作系列 文章目录 系列文章目录前言五、特殊用法5.1 取值范围表示5.2 对输入值取值范围进行限定5.3 控制多个While循环停止运行。5.4 获取按钮上的文本5.5 获取按钮上的文本【进阶】 六、使用步骤1.引入库2.读入数据 七、其余功能7.…

二叉树以及堆的实现

树 树的定义及概念 树是⼀种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09; 个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像⼀棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有⼀个特殊的结点&#xff0c;称…

[Meachines] [Easy] Admirer Adminer远程Mysql反向+Python三方库函数劫持权限提升

信息收集 IP AddressOpening Ports10.10.10.187TCP:21,22,80 $ nmap -p- 10.10.10.187 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.3 22/tcp open ssh OpenSSH 7.4p1 Debian 10deb9u7 (protocol 2.0) | ssh-hostkey: | …

Redis:十大数据类型

键&#xff08;key&#xff09; 常用命令 1. 字符串&#xff08;String&#xff09; 1.1 基本命令 set key value 如下&#xff1a;设置kv键值对&#xff0c;存货时长为30秒 get key mset key value [key value ...]mget key [key ...] 同时设置或者获取多个键值对 getrange…

万物互联,触手可及“2024南京智慧城市,物联网,大数据展会”

在金秋送爽的11月&#xff0c;南京这座历史悠久而又充满活力的城市&#xff0c;即将迎来一场科技盛宴——2024南京智慧城市、物联网、大数据展会。这不仅是一场技术的集会&#xff0c;更是未来生活蓝图的预览&#xff0c;它汇聚了全球顶尖的科技企业、创新者及行业精英&#xf…

制作PE启动U盘 预防电脑无法正常开机进入系统

PE 是一种简化版的便携式操作系统&#xff0c;它可以直接装载在 U 盘里运行。通过它我们能做非常多的应急操作&#xff0c;比如删除文件、卸载软件、拷贝数据、格式化硬盘、重装系统等。 在电脑无法正常开机进入系统&#xff0c;身边又没有其他电脑时&#xff0c;手头有个 PE …

Corsearch 用 ClickHouse 替换 MySQL 进行内容和品牌保护

本文字数&#xff1a;3357&#xff1b;估计阅读时间&#xff1a;9 分钟 作者&#xff1a;ClickHouse Team 本文在公众号【ClickHouseInc】首发 Chase Richards 自 2011 年在初创公司 Marketly 担任工程负责人&#xff0c;直到 2020 年公司被收购。他现在是品牌保护公司 Corsear…