牛客网刷题之链表(一)

news2024/11/22 23:40:07

链表

  • NB1 删除链表峰值
  • NB2 牛群排列去重
  • NB3 调整牛群顺序
  • NB4 牛群的重新分组
  • NB5 牛群的重新排列
  • NB6 合并两群能量值(合并有序单链表)
  • NB7 牛群的能量值(单链表相加)

以下题全部出自牛客网。
题目题目考察的知识点链表:
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表的分类有单向、双向等多种类型。其中单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。单链表中的数据是以结点来表示的,每个结点的构成:元素 (数据元素 的映象) + 指针 (指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
与链表有关的题基本都是插入,删除,交换顺序等,解决这些问题通常将链表的指针进行修改,有的简单有的复杂;比如删除链表的头结点和别的结点代码不一样,或者容易对空结点容易解引用等,这时可以加一个头结点,一些问题就可以得到很好的解决。

NB1 删除链表峰值

描述:
农场主人有一群牛,他给每只牛都打了一个编号,编号由整数表示。这些牛按照编号的大小形成了一个链表。现在农场主人想删除链表中比前后结点值都大的牛的编号,你能帮他设计一个算法来实现这个功能吗?注意,只考虑删除前,首尾的牛的编号不删除。

在这里插入图片描述

问题分析: 要删除链表中比前后结点值都大的编号,并且只考虑删除前,首尾的编号不删除,所以用三个指针:prev,cur,next,prev指向删除结点的前一个结点,cur指向将要删除的结点,next指向删除结点的下一个,这样就能很容易将结点连接起来。
代码如下:

ListNode* deleteNodes(ListNode* head)
{
    // write code here
	ListNode* prev = head, * cur = prev->next, * next = cur->next;
	while (next)
	{
		if ((cur->val > prev->val) && (cur->val > next->val)) //删除cur,prev不移动
		{
			prev->next = next;
			free(cur);
		}
		else //不删除cur,prev向后移动
		{
			prev = prev->next;
		}
		cur = next;
		next = cur->next;
	}

	return head;
}

NB2 牛群排列去重

描述:
农场里有一群牛,每头牛都有一个独特的编号,编号由一个整数表示,整数范围是[0, 200]。牛群中的牛用单链表表示,链表已经按照非降序排列。
因为一些事故,导致一头牛可能多次出现在链表中。给你一个链表的头 head,删除链表中所有重复的编号,只留下所有牛的不重复编号。返回已排序的链表。
在这里插入图片描述
问题分析: 这道题就是单链表的删除,可以保留相同值结点的第一个,用三个指针:prev,cur,next,prev指向删除结点的前一个结点,cur指向将要删除的结点,next指向删除结点的下一个。

代码如下:

ListNode* deleteDuplicates(ListNode* head)
{
	// write code here
	if (head == nullptr)
		return head;
	ListNode* prev = head, * cur = prev->next, * next = cur->next;
	while (cur) //因为可能需要删除结尾,所以结束标志为cur
	{
		if (cur->val == prev->val)
		{
			prev->next = next;
			free(cur);
		}
		else 
		{
			prev = prev->next;
		}
		cur = next;
		next = cur->next;
	}
}

NB3 调整牛群顺序

描述:
农场里有一群牛,每头牛都有一个编号,编号由一个整数表示,整数范围是[0, 100]。牛群中的牛用单链表表示。
现在,农场主想要调整牛群的顺序。给你一个链表,将链表中的倒数第 n 个结点移到链表的末尾,并且返回调整后的链表的头结点。
在这里插入图片描述
问题分析: 首先找出倒数第 n 个结点,使用快慢指针方法,然后这个倒数第 n 个结点可能是头结点,头结点可能是需要改变的,所以有两种思路:第一种,将改变的结点判断一下,若为头结点,则修改头结点的指针,若不是,则正常处理;第二种,构造一个新的头结点,然后再按正常处理就行(构造新的头结点可以很好的处理问题)。

如下为第二种思路,代码如下:

//NB3 调整牛群顺序
ListNode* moveNthToEnd(ListNode* head, int n)
{
    // write code here
    if (n == 1)
        return head;

    ListNode* newhead = new ListNode(-1);
    newhead->next = head;
    ListNode* cur = newhead;
    ListNode* prev = newhead, * end = newhead; //prev指向的是交换结点的前一个指针

    //寻找倒数第k个结点使用快慢指针方法
    for (int i = 0; i < n; ++i)
    {
        end = end->next;
    }
    while (end->next)
    {
        prev = prev->next;
        end = end->next;
    }

    cur = prev->next;
    prev->next = cur->next;
    end->next = cur;
    cur->next = nullptr;
    head = newhead->next; //头结点可能被改变,所以更新头结点
    free(newhead);

    return head;
}

NB4 牛群的重新分组

描述: 农场里有一群牛,每头牛都有一个编号,编号由一个整数表示,整数范围是[0, 1000]。牛群中的牛用单链表表示。
现在,农场主想要重新分组牛群。给定一个单链表的头指针 head 和一个整数 k,每 k 个节点一组进行翻转,请你返回修改后的牛群链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
在这里插入图片描述
问题分析: 这道题需要改变头结点,所以新建一个头结点,然后需要翻转单链表,翻转单链表可以用链表头插, 将需要翻转的结点一个一个头插到某个结点的后面,总之,这道题用头插不是很容易。

代码如下:

int isreverse(ListNode*& tmp, int& k) //判断是否翻转
{
    int n = 0;
    while (tmp)
    {
        ++n;
        if (n == k)
        {
            if (tmp->next == nullptr) //因为如果最后一个结点头插,最后一个结点的指针将头插到前一个,此时tmp后面就不为空,所以这里附空
            {
                tmp = nullptr;
            }
            return 1;
        }
        tmp = tmp->next;
    }
    return 0;
}
ListNode* reverseKGroup(ListNode* head, int k)
{
    // write code here
    ListNode* newhead = new ListNode(-1);
    newhead->next = head;
    ListNode* prev = newhead; //prev是开始进行翻转的前一个结点
    ListNode* end = prev->next; //end是每次头插第一个结点
    //头插k个结点
    ListNode* cur = prev->next; //当前节点
    ListNode* next = cur->next; //下一个结点
    while (cur)
    {
        ListNode* tmp = cur; //tmp进行遍历
        if (isreverse(tmp, k)) //够翻转,进行翻转
        {
            for (int i = 0; i < k; ++i)
            {
                if (i == 0)
                {
                    end = cur;
                }
                //头插
                cur->next = prev->next; 
                prev->next = cur;
                //更新结点
                cur = next;
                if (cur->next)
                    next = next->next;

            }
            //连接结点
            prev = end;
            end->next = cur;
        }
        else
            break;
        if (tmp == nullptr) //如果全部翻转,将最后一个结点指空,end是每次头插第一个结点,也就是最后一个结点
        {
            end->next = nullptr;
            break;
        }
    }

    head = newhead->next;
    delete(newhead);

    return head;
}

NB5 牛群的重新排列

描述:
农场里有一群牛,每头牛都有一个编号,编号由一个整数表示,整数范围是[-500, 500]。牛群中的牛用单链表表示。
现在,农场主想要改变牛群的排列顺序。给定一个单链表的头指针 head 和两个整数 left 和 right,其中 left <= right。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的牛群链表。

在这里插入图片描述
问题分析:这道题可以用头插来做,也可以用栈来做,相比上一道要容易些,大致思路和上一个差不多;prev指向第一个翻转结点的前一个,end指向第一个翻转的结点,cur指向翻转的结点,next指向翻转结点的下一个结点,然后对第left到第right个的结点头插,最后在将头插的和未投插的结点连接起来。

ListNode* reverseBetween(ListNode* head, int left, int right)
{
    // write code here
    ListNode* newhead = new ListNode(-501);
    newhead->next = head;

    ListNode* prev = newhead; //prev是开始进行翻转的前一个结点
    int n = 1;
    while (n < left)
    {
        prev = prev->next;
        ++n;
    }
    ListNode* cur = prev->next; //cur是需要翻转的结点
    ListNode* next = cur->next; //next是翻转的结点的下一个结点
    ListNode* end = cur; //end是第left个结点
    while (left <= right)
    {
        //头插
        cur->next = prev->next;
        prev->next = cur;
        //更新结点
        cur = next;
        if (next)
            next = next->next;
        ++left;
    }
    //连接
    end->next = cur;

    head = newhead->next;
    delete newhead;

    return head;
}

NB6 合并两群能量值(合并有序单链表)

描述:
农场里有两群牛,每群牛都有一定的能量值。能量值由一个整数表示,整数范围是[-100, 100]。每群牛的能量值已经按照非递增顺序排列,并存储在链表中。
现在,你需要将这两群牛的能量值合并为一个新的非递增链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
在这里插入图片描述
题目分析:这道题就是合并两个有序单链表,首先判断l1,l2是否有空,1. 若都为空,则返回空;2. 若一个为空,另一个不为空,则返回不为空的一个;3. 两个都不为空,开始遍历两个链表,比较两个结点的大小,插入大的那一个结点,若遍历某个链表为空,则将不为空的链表进行插入,否则继续遍历。
代码如下:

ListNode* mergeEnergyValues(ListNode* l1, ListNode* l2)
{
    // write code here
    ListNode* head, * cur;
    //先判断是否有空
    if (l1 == nullptr && l2 != nullptr)
        return l2;
    else if (l1 != nullptr && l2 == nullptr)
        return l1;
    else if (l1 == nullptr && l2 == nullptr)
        return nullptr;

    //给head附头
    if (l1->val >= l2->val)
    {
        head = cur = l1;
        l1 = l1->next;
    }
    else
    {
        head = cur = l2;
        l2 = l2->next;
    }
    while (l1 || l2)//两个都空结束
    {
        //判断遍历时是否有空
        if (l1 == nullptr && l2 != nullptr)
        {
            cur->next = l2;
            return head;
        }
        else if (l1 != nullptr && l2 == nullptr)
        {
            cur->next = l1;
            return head;
        }
        if (l1->val >= l2->val)
        {
            cur->next = l1;
            cur = cur->next;
            l1 = l1->next;
        }
        else
        {
            cur->next = l2;
            cur = cur->next;
            l2 = l2->next;
        }
    }
    cur->next = nullptr;
    return head;
}
ListNode* mergeEnergyValues(ListNode* l1, ListNode* l2)
{
    if (!l1 || !l2)
        return l1 ? l1 : l2;
    ListNode* head = new ListNode(-1);
    ListNode* cur = head, * p1 = l1, * p2 = l1;
    while (l1 && l2)
    {
        if (p1->val > p2->val)
        {
            cur->next = p1;
            p1 = p1->next;
        }
        else
        {
            cur->next = p2;
            p2 = p2->next;
        }
        cur = cur->next;
    }
    //至少有一个链表为空,cur->next连接不为空的链表
    cur->next = (p1 ? p1 : p2);

    cur = head->next;
    delete head;
    return cur;
}

NB7 牛群的能量值(单链表相加)

描述:
农场里有两群牛,每群牛都有一定的能量值。能量值由一个非负整数表示,且每头牛的能量值只有一位数字。能量值按照逆序的方式存储在链表中,即链表的第一个节点表示个位,第二个节点表示十位,以此类推。
现在,你需要将这两群牛的能量值相加,然后以相同的逆序形式返回表示和的链表。
注意:除了数字0之外,这两个数都不会以0开头。

在这里插入图片描述

问题分析:单链表相加,遍历两个链表,将两个链表相加,注意链表的长短不一样,还有就是最后一位需不需要进位。

ListNode* addEnergyValues(ListNode* l1, ListNode* l2)
{
    ListNode* head = new ListNode(-1);
    ListNode* cur = head;
    int m = 0; //是否进位
    //有一个链表为空则退出
    while (l1 && l2)
    {
        int n = l1->val + l2->val + m;
        m = 0;
        if (n > 9)
            m = 1;
        cur->next = new ListNode(n%10);
        cur = cur->next;
        l1 = l1->next;
        l2 = l2->next;
    }
    if (l1)
        l2 = l1;
    //if处理后,l2一定不为空
    while (l2)
    {
        int n = l2->val + m;
        m = 0;
        if (n > 9)
            m = 1;
        cur->next = new ListNode(n % 10);
        cur = cur->next;
        l2 = l2->next;
    }
    //处理最后进位的数
    if (m == 1)
        cur->next = new ListNode(m);
    return head->next;
}

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

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

相关文章

Element Plus 日期选择器

计算开始日期到结束日期的总天数 结构 <el-form-item label"计划开始时间" required prop"StartTime"><el-date-pickertype"date"v-model"ruleForm.StartTime":disabled-date"StartTime"placeholder"计划开始…

pytorch工具——使用pytorch构建一个分类器

目录 分类器任务和数据介绍训练分类器的步骤在GPU上训练模型 分类器任务和数据介绍 训练分类器的步骤 #1 import torch import torchvision import torchvision.transforms as transformstransformtransforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.…

SpringCloud学习路线(8)—— Docker

一、Docker的开始 &#xff08;一&#xff09;项目部署问题&#xff1a; 依赖关系复杂&#xff0c;容易出现兼容性问题开发、测试、生产环境有差异 &#xff08;二&#xff09;Docker如何解决问题&#xff1f; 1、依赖兼容问题 &#xff08;1&#xff09;将应用的Libs&…

垃圾回收之三色标记法(Tri-color Marking)

关于垃圾回收算法&#xff0c;基本就是那么几种&#xff1a;标记-清除、标记-复制、标记-整理。在此基础上可以增加分代&#xff08;新生代/老年代&#xff09;&#xff0c;每代采取不同的回收算法&#xff0c;以提高整体的分配和回收效率。 无论使用哪种算法&#xff0c;标记…

(已解决)RuntimeError: Java gateway process exited before sending its port number

今天用Pycharm远程使用pysaprk解释器时&#xff0c;跑代码出现了这个错误&#xff1a; RuntimeError: Java gateway process exited before sending its port number 找了好多博客都没解决问题&#xff0c;有说重装spark的&#xff0c;有说本地配Java_home的&#xff0c;后面我…

[C语言刷题]杨氏矩阵、返回型参数

本文包含知识点 杨氏矩阵极其解法函数return多个值的四种方法 题目&#xff1a; 杨氏矩阵 有一个数字矩阵&#xff0c;矩阵的每行从左到右是递增的&#xff0c;矩阵从上到下是递增的&#xff0c;请编写程序在这样的矩阵中查找某个数字是否存在。 要求&#xff1a;时间复杂度小于…

js 在浏览器窗口关闭后还可以不中断网络请求

有个需求&#xff0c;我们需要在用户发送数据过程中&#xff0c;如果用户关闭了网页(包括整个浏览器关闭)&#xff0c;不要中断数据传递 目前XMLHttpRequest对象是不支持的 http服务器 为了测试效果我们用nodejs写了个http服务器代码 文件名为httpServer.js如下&#xff0c;…

获取大疆无人机的飞控记录数据并绘制曲线

机型M350RTK&#xff0c;其飞行记录文件为加密的&#xff0c;我的完善代码如下 gitgithub.com:huashu996/DJFlightRecordParsing2TXT.git 一、下载安装官方的DJIFlightRecord git clone gitgithub.com:dji-sdk/FlightRecordParsingLib.git飞行记录文件在打开【我的电脑】&am…

Windows nvm 安装后webstrom vue项目编译报错,无法识别node

1 nvm安装流程 卸载原先nodejs用管理员权限打开exe安装nvmnvm文件夹和nodejs文件夹 都授权Authenticated Users 完全控制nvm list availablenvm install 16.20.1nvm use 16.20.1输入node和npm检查版本命令&#xff0c;正常显示确认系统变量和用户变量都有nvm 和nodejs 2 bug情…

数学建模-聚类算法 系统(层次)聚类

绝对值距离:网状道路 一般用组间和组内距离 聚类的距离计算如何选取&#xff1a;看结果是否解释的通&#xff0c;选择一种结果解释的通的方法。

【数据挖掘】将NLP技术引入到股市分析

一、说明 在交易中实施的机器学习模型通常根据历史股票价格和其他定量数据进行训练&#xff0c;以预测未来的股票价格。但是&#xff0c;自然语言处理&#xff08;NLP&#xff09;使我们能够分析财务文档&#xff0c;例如10-k表格&#xff0c;以预测股票走势。 二、对自然语言处…

【转载+修改】pytorch中backward求梯度方法的具体解析

原则上&#xff0c;pytorch不支持张量对张量的求导&#xff0c;它只支持标量对张量的求导 我们先看标量对张量求导的情况 import torch xtorch.ones(2,2,requires_gradTrue) print(x) print(x.grad_fn)输出&#xff0c;由于x是被直接创建的&#xff0c;也就是说它是一个叶子节…

Vue.js uni-app 混合模式原生App webview与H5的交互

在现代移动应用开发中&#xff0c;原生App与H5页面之间的交互已经成为一个常见的需求。本文将介绍如何在Vue.js框架中实现原生App与H5页面之间的数据传递和方法调用。我们将通过一个简单的示例来展示如何实现这一功能。附完整源码下载地址:https://ext.dcloud.net.cn/plugin?i…

Java集成openAi的ChatGPT实战

效果图&#xff1a; 免费体验地址&#xff1a;AI智能助手 具体实现 public class OpenAiUtils {private static final Log LOG LogFactory.getLog(OpenAiUtils.class);private static OpenAiProxyService openAiProxyService;public OpenAiUtils(OpenAiProxyService openAiP…

【C++】入门 --- 命名空间

文章目录 &#x1f36a;一、前言&#x1f369;1、C简介&#x1f369;2、C关键字 &#x1f36a;二、命名冲突&#x1f36a;三、命名空间&#x1f369;1、命名空间定义&#x1f369;2、命名空间的使用 &#x1f36a;四、C输入&输出 &#x1f36a;一、前言 本篇文章是《C 初阶…

Data Transfer Object-DTO,数据传输对象,前端参数设计多个数据表对象

涉及两张表的两个实体对象 用于在业务逻辑层和持久层&#xff08;数据库访问层&#xff09;之间传输数据。 DTO的主要目的是将多个实体&#xff08;Entity&#xff09;的部分属性或多个实体关联属性封装成一个对象&#xff0c;以便在业务层进行数据传输和处理&#xff0c;从而…

八、HAL_UART(串口)的接收和发送

1、开发环境 (1)Keil MDK: V5.38.0.0 (2)STM32CubeMX: V6.8.1 (3)MCU: STM32F407ZGT6 2、UART和USART的区别 2.1、UART (1)通用异步收发收发器&#xff1a;Universal Asynchronous Receiver/Transmitter)。 2.2、USART (1)通用同步异步收发器&#xff1a;Universal Syn…

【《R4编程入门与数据科学实战》——一本“能在日常生活中使用统计学”的书】

《R 4编程入门与数据科学实战》的两名作者均为从事编程以及教育方面的专家&#xff0c;他们用详尽的语言&#xff0c;以初学者的角度进行知识点的讲解&#xff0c;每个细节都手把手教学,以让读者悉数掌握所有知识点&#xff0c;在每章的结尾都安排理论与实操相结合的习题。与同…

banner轮播图实现、激活状态显示和分类列表渲染、解决路由缓存问题、使用逻辑函数拆分业务(一级分类)【Vue3】

一级分类 - banner轮播图实现 分类轮播图实现 分类轮播图和首页轮播图的区别只有一个&#xff0c;接口参数不同&#xff0c;其余逻辑完成一致 适配接口 export function getBannerAPI (params {}) {// 默认为1 商品为2const { distributionSite 1 } paramsreturn httpIn…

VTK是如何显示一个三维立体图像的

VTK是如何显示一个三维立体图像的 1、文字描述2、图像演示 1、文字描述 2、图像演示