数据结构--单链表OJ题

上文回顾---单链表

这章将来做一些链表的相关题目


目录

1.移除链表元素

2.反转链表

3.链表的中间结点

4.链表中的倒数第k个结点

5.合并两个有序链表

6.链表分割

7.链表的回文结构

8.相交链表

9.环形链表

​编辑 

10.环形链表II

​编辑 ​编辑


1.移除链表元素

 

 思路:我们可以通过循环链表,判断结点的val与给出的val是否一致,一致则跳过该结点即可

由于我们是跳过某个结点,那么就会让这个结点的上一个结点和下一个结点进行关联;所以我们以某结点的next的val去判断;所以对于头结点来说,我们还要创建一个结点连接着头结点;

我们自己创建一个结点,还可以规避头指针为空的问题; 

答案:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val){//哨兵位struct ListNode* newhead=malloc(sizeof(struct ListNode));newhead->next=head;struct ListNode* cur=newhead;while(cur->next){//判断下一个的值if(cur->next->val==val){cur->next=cur->next->next;}else{cur=cur->next;}}//返回头指针return newhead->next;}

2.反转链表

 

 思路:这道题实际上就是让结点的next改变即可;

所以在这里,我们创建3个指针prev,cur,next,让cur的next指向prev,然后进行指针移动,循环往复;一开始的prev指向NULL;如果head为空,那么就特殊处理,直接返回空;

 

答案:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* reverseList(struct ListNode* head){//特殊条件if(head==NULL){return NULL;}struct ListNode* cur=head;struct ListNode* prev=NULL;struct ListNode* next=head->next;//移动指针while(cur){cur->next=prev;prev=cur;cur=next;//判断nextif(next!=NULL){next=next->next;}}return prev;
}

3.链表的中间结点

 

 思路1:我们可以先算出链表的总长度,然后再取中间结点的位置

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* middleNode(struct ListNode* head){//先确定链表长度int i=0;struct ListNode* node=head;while(node!=NULL){node=node->next;i++;}//确定中间节点位置int k=i/2;for(int i=0;i<k;i++){head=head->next;}return head;
}

思路2:利用快慢指针的思想

我们只有在链表遍历到为NULL才知道结束,那么我们是否可以利用当指针到达末尾时就知道中间位置的思想呢?

这里我们用到的快慢指针思想就可以解决该问题,利用它们的速度差,走到的长度就是不一样的;

快指针一次跨越2个结点,而慢指针一次跨越1个结点,等到快指针到达末尾时,慢指针刚好到达中间位置

对于两个中间结点的,我们需要让快指针走到NULL才能达到第二个结点;而一个中间结点的,只需要让快指针走到最后一个结点即可

答案:

struct ListNode* middleNode(struct ListNode* head){//快慢指针struct ListNode* slow,*fast;slow=fast=head;//移动while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}return slow;
}

 


4.链表中的倒数第k个结点

思路:这里还是利用到快慢指针的思想;还是利用快指针到达末尾,然后得知结点的思路;

只不过这里利用的是快慢之间的相对距离,上一题是快慢之间的相对速度;

我们可以让fast指针先走k步,然后在让slow和fast同时走,那么当fast指针到达NULL时, slow刚好到达返回的结点;

 这里要注意的几个特殊情况:头指针为空;k的大小超过链表长度

答案:

/*** struct ListNode {*	int val;*	struct ListNode *next;* };*//*** * @param pListHead ListNode类 * @param k int整型 * @return ListNode类*/
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {if(pListHead==NULL){return NULL;}//利用相对距离struct ListNode* slow,*fast;slow=fast=pListHead;//先走k步while(k&&fast){fast=fast->next;k--;}if(k>0){return NULL;}while(fast){slow=slow->next;fast=fast->next;}return slow;}

 


5.合并两个有序链表

 

 思路:这里我们先创建一个结点,通过判断两链表的头结点的val大小,来决定连接着哪个

然后循环遍历,移动指针,执行同样的操作;

 当某一链表结束了,需要链接另一条链表剩余的结点;

答案:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){//哨兵位struct ListNode* prehead=malloc(sizeof(struct ListNode));//比大小struct ListNode* prev=prehead;while(list1&&list2){if(list1->val<list2->val){prev->next=list1;list1=list1->next;prev=prev->next;}else{prev->next=list2;list2=list2->next;prev=prev->next;}}//判断哪个链表有剩余prev->next=list1==NULL?list2:list1;return prehead->next;
}

 


6.链表分割

 

 思路:我们可以创建2个结点,第一个结点连接着比x小的结点,第二个连接着>=x的结点

最后将着两个新链表连接在一起;

这里要注意,最后的结点要接空,否则该结点的next保持不变,可能会造成环,将会报错;

 

答案:

/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:ListNode* partition(ListNode* pHead, int x) {struct ListNode* prevHead1=(struct ListNode*)malloc(sizeof(ListNode));struct ListNode* prevHead2=(struct ListNode*)malloc(sizeof(ListNode));ListNode* tail1=prevHead1;ListNode* tail2=prevHead2;while(pHead){if(pHead->val<x){tail1->next=pHead;tail1=tail1->next;}else {tail2->next=pHead;tail2=tail2->next;}pHead=pHead->next;}//连接tail1->next=prevHead2->next;//尾置空tail2->next=NULL;return prevHead1->next;}
};

 


7.链表的回文结构

思路:这里我们没有办法从后走向前,单链表是单向的;所以我们可以只能从前往后走;

我们可以先找到中间结点,然后对中间结点之后的链表进行倒转,最后通过中间指针和头指针遍历,判断对应的val是否相同即可

 

 

答案:

/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:struct ListNode* middleNode(struct ListNode* head){//快慢指针struct ListNode* slow,*fast;slow=fast=head;//移动while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}return slow;}struct ListNode* reverseList(struct ListNode* head){//特殊条件if(head==NULL){return NULL;}struct ListNode* cur=head;struct ListNode* prev=NULL;struct ListNode* next=head->next;//移动指针while(cur){cur->next=prev;prev=cur;cur=next;//判断nextif(next!=NULL){next=next->next;}}return prev;}bool chkPalindrome(ListNode* head) {ListNode* mid=middleNode(head); //找中间ListNode* rmid=reverseList(mid); //中间位置后面倒置//比较while(rmid){if(head->val!=rmid->val){return false;}head=head->next;rmid=rmid->next;}return true;}
};

 


8.相交链表

 

 

 

 

思路:我们要看作是两条链表,然后后半部分连接是相同部分的结点

发现相交的链表的相交部分都是一样的;我们可以利用它们的尾结点来判断是否相交

对于没有相交的部分,我们无法确保它们的长度;所以我们可以先让比较长的链表先走长度差,然后再一起访问;当访问的结点一致时,表明找到了相交的第一个结点;

答案:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {int lenthA=1,lenthB=1;struct ListNode* curA=headA;struct ListNode* curB=headB;//计算链表长度while(curA->next){++lenthA;curA=curA->next;}while(curB->next){++lenthB;curB=curB->next;}//尾节点判断,不一样说明没有香蕉if(curA!=curB){return NULL;}//长度先走差距步struct ListNode* longList=headA,*shortList=headB;int abs=fabs(lenthA-lenthB);if(lenthA<lenthB){longList=headB;shortList=headA;}while(abs--){longList=longList->next;}//找到相同的交点while(longList!=shortList){longList=longList->next;shortList=shortList->next;}return longList;
}

 这里要注意,curA,curB只能走到尾结点,目的是为了判断它们是否相同,是否相交;


9.环形链表

 

 

 

思路:还是利用快慢指针的思想;

假设有环,通过快慢指针, 快指针一定先进入环中,当慢指针进入环时,让快指针去追逐慢指针

如果快指针走到了空,表示没有环;

这里我们让快指针走两步,让慢指针走1步;当慢指针进入环时,假设快指针到慢指针距离为N,那么没走一次,它们之间的距离就会减1,直至减到N为0,表示快指针追到了

 

答案:

 

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
bool hasCycle(struct ListNode *head) {//快慢指针//赛道追逐问题struct ListNode* slow=head;struct ListNode* fast=head;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;if(fast==slow){return  true;}}return false;}

这里为什么不让快指针走3步,让慢指针走1步呢?

假设慢指针进入循环后它们之间距离为N

每走一次,它们之间的距离就会减2,N-2,N-4……

如果N为偶数,那么减到最后可以为0,那么就表示追上了,

而如果N为奇数,那么追到最后为1或者-1,不是差一点追上,就是追过了,所以它们的相遇还要考虑环的周长,追过了距离就变为周长-1;

 

到最后,可能追上了,可能一直遇不到;

例如:

 

当slow在左边,fast就在右边;slow在右边,fast就在左边;永远都遇不到

所以为了方便解决问题,就让快指针走2步即可; 


10.环形链表II

 

 

思路:这里我们要在第9题的思想上再引入数学的思想;

假设起点到环入口距离为L,环周长为C,入口到相遇点距离X;

 

fast指针走的距离是slow指针的2倍,所以fast指针会先进入环中, fast可能会在环中绕几圈,我们设为n

那么slow指针走的距离为L+X;

fast指针走的距离为L+n(n>=1)*C+X,fast指针要追上slow,至少要绕一圈环

那么通过它们之间的关系

得到2(L+X)=L+n*C+X

最终得到L=(n-1)*C+C-X;

 也就是说,L的距离会等于n圈环的周长加上相遇点到入口的距离;

那么将得出结论:

一个指针从起点走,一个指针从相遇点走,它们将会在入口点相遇

 答案:

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
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=fast;while(meet!=head){meet=meet->next;head=head->next;}return meet;}}return NULL;
}

通过分析之后,我们不需要管那些未知数;

假设L很长,环很小,那么在相遇点的指针就会在环中多走几圈;

假设L很短,那么相遇点到入口点的距离就刚好是L的长度;

所以在写代码中,我们只需要知道起始的指针和相遇点的指针最终会相遇,且就是入口点。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023暑假牛客多校6- E.Sequence

题目描述 You have an array of elements . For each task, you have three integers . Ask whether you can find an array of integers satisfy: are the multiplies of 2 Specially, if , it should satisfy is the multiply of 2 We define . If possible, print…

Java课题笔记~ 动态SQL详解

一、动态 sql 是什么&#xff1f; 1、动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中&#xff0c;开发人员通常需要手动拼接 SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。 例如&#xff0c;拼接时要确保添加了必要的空格&#xff0c;还要…

cnvd通用型证书获取姿势

因为技术有限&#xff0c;只能挖挖不用脑子的漏洞&#xff0c;平时工作摸鱼的时候通过谷歌引擎引擎搜索找找有没有大点的公司有sql注入漏洞&#xff0c;找的方法就很简单&#xff0c;网站结尾加上’&#xff0c;有异常就测试看看&#xff0c;没有马上下一家&#xff0c;效率至上…

Day12-1-Webpack前端工程化开发

Webpack前端工程化 1 案例-webpack打包js文件 1 在index.html中编写代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><me…

20天学会rust(二)rust的基础语法篇

在第一节&#xff08;20天学rust&#xff08;一&#xff09;和rust say hi&#xff09;我们配置好了rust的环境&#xff0c;并且运行了一个简单的demo——practice-01&#xff0c;接下来我们将从示例入手&#xff0c;学习rust的基础语法。 首先来看下项目结构&#xff1a; 项目…

QtWebApp开发https服务器,完成客户端与服务器基于ssl的双向认证,纯代码操作

引言&#xff1a;所谓http协议&#xff0c;本质上也是基于TCP/IP上服务器与客户端请求和应答的标准&#xff0c;web开发中常用的http server有apache和nginx。Qt程序作为http client可以使用QNetworkAccessManager很方便的进行http相关的操作。Qt本身并没有http server相关的库…

zabbix监控mysql容器主从同步状态并告警钉钉/企业微信

前言&#xff1a;被监控的主机已经安装和配置mysql主从同步&#xff0c;和zabbix-agent插件。 mysql创建主从同步&#xff1a;http://t.csdn.cn/P4MYq centos安装zabbix-agent2&#xff1a;http://t.csdn.cn/fx74i mysql主从同步&#xff0c;主要监控这2个参数指标&#xf…

Maven-学习笔记

文章目录 1. Maven简介2.Maven安装和基础配置3.Maven基本使用4.Maven坐标介绍 1. Maven简介 概念 Maven是专门用于管理和构建Java项目的工具 主要功能有: 提供了一套标准化的项目结构提供了一套标准化的构建流程&#xff08;编译&#xff0c;测试&#xff0c;打包&#xff0c;…

微信小程序中的全局数据共享(状态管理)使用介绍

开发工具&#xff1a;微信开发者工具Stable 1.06 一、状态管理简介 微信小程序全局状态是指可以在不同页面之间共享的数据或状态。 它可以存储用户的登录状态、个人信息、全局配置信息等。 二、安装MobX 1、安装NPM 在资源管理器的空白地方点右键&#xff0c;选择“在外部…

无涯教程-Perl - endhostent函数

描述 此函数告诉系统您不再希望使用gethostent从hosts文件读取条目。 语法 以下是此函数的简单语法- endhostent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perlwhile( ($name, $aliases, $addrtype, $length, addrs)gethostent() ) …

5个可以创意灵感的AI绘画工具

当设计灵感耗尽&#xff0c;陷入创作瓶颈时&#xff0c;人工智能艺术生成器可能会为您提供新的启示。这些基于深度学习和发展“神经网络”的工具可以将输入的文本描述或图像转换成各种风格的艺术作品&#xff0c;并提供丰富的风格参数和材料库&#xff0c;让您可以自由调整和创…

【Linux】网络套接字知识点补足

目录 1 地址转换函数 1.1 字符串转in_addr的函数: 1.2 in_addr转字符串的函数: 1.3 关于inet_ntoa 2 TCP协议通讯流程 1 地址转换函数 本节只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP 地址但是我们通常用点分十进制的字符串…

【Java split】split() 函数分割空字符串后数组长度为1的原因以及规避措施(105)

问题现象: import java.util.ArrayList; import java.util.Arrays; import java.util.List;public class test06 {public static void main(String[] args) {// Java split()函数 分割空字符串长度为1的解释&#xff1b;String s2 "";String[] arr2 s2.split(&quo…

Spring 容器原始 Bean 是如何创建的?

以下内容基于 Spring6.0.4。 这个话题其实非常庞大&#xff0c;我本来想从 getBean 方法讲起&#xff0c;但一想这样讲完估计很多小伙伴就懵了&#xff0c;所以我们还是一步一步来&#xff0c;今天我主要是想和小伙伴们讲讲 Spring 容器创建 Bean 最最核心的 createBeanInstan…

【Nginx】静态资源部署、反向代理、负载均衡

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ nginx静态资源部署、反向代理、负载均衡 &…

今年这情况,真想考研了!

眼下&#xff0c;又是一年的毕业季&#xff0c;超千万规模的毕业生大军如“丧尸围城”&#xff0c;浩浩荡荡地涌入职场。与他们一路同行的还有因疫情影响2022年离校未就业的毕业生&#xff0c;以及那些不幸“被优化”的职场人。 今年&#xff0c;1158 万毕业生&#xff0c;再加…

全面解析大语言模型的工作原理

当ChatGPT在去年秋天推出时&#xff0c;在科技行业乃至世界范围内引起了轰动。当时&#xff0c;机器学习研究人员尝试研发了多年的语言大模型&#xff08;LLM&#xff09;&#xff0c;但普通大众并未十分关注&#xff0c;也没有意识到它们变得多强大。 如今&#xff0c;几乎每个…

ASP.NET Core MVC -- 将视图添加到 ASP.NET Core MVC 应用

Index页 右键单击“视图”文件夹&#xff0c;然后单击“添加”>>“新文件夹”&#xff0c;并将文件夹命名为“HelloWorld”。 右键单击“Views/HelloWorld”文件夹&#xff0c;然后单击“添加”>“新项”。 在“添加新项 - MvcMovie”对话框中&#xff1a; 在右上…

区块链实验室(15) - 编译FISCO BCOS的过程监测

首次编译开源项目&#xff0c;一般需要下载很多依赖包&#xff0c;尤其是从github、sourceforge等下载依赖包时&#xff0c;速度很慢&#xff0c;编译进度似乎没有一点反应&#xff0c;似乎陷入死循环&#xff0c;似乎陷入一个没有结果的等待。本文提供一种监测方法&#xff0c…

ClickHouse SQL与引擎--基本使用(一)

1.查看所有的数据库 show databases; 2.创建库 CREATE DATABASE zabbix ENGINE Ordinary; ATTACH DATABASE ck_test ENGINE Ordinary;3.创建本地表 CREATE TABLE IF NOT EXISTS test01(id UInt64,name String,time UInt64,age UInt8,flag UInt8 ) ENGINE MergeTree PARTI…