【编织时空三:探究顺序表与链表的数据之旅】

本章重点

  • 链表OJ题

1. 删除链表中等于给定值 val 的所有结点。 OJ链接

思路一:删除头结点时另做考虑(由于头结点没有前一个结点)

struct ListNode* removeElements(struct ListNode* head, int val) {assert(head);struct ListNode* cur = head;struct ListNode* curPrev = NULL;while (cur != NULL){if (cur->val != val){curPrev = cur;cur = cur->next;}else{if (cur == head){head = cur->next;free(cur);cur = head;}else{curPrev->next = cur->next;free(cur);cur = curPrev->next;}}}return head;
}

思路二:添加一个虚拟头结点,删除头结点就不用另做考虑

struct ListNode* removeElements(struct ListNode* head, int val)
{struct ListNode* cur = head;struct ListNode* newhead = NULL;struct ListNode* tail = NULL;while (cur != NULL){if (cur->val == val){struct ListNode* del = cur;cur = cur->next;free(del);}else{//尾插if (tail == NULL){newhead = tail = cur;}else{tail->next = cur;tail = tail->next;}cur = cur->next;}}if (tail)//如果最后一个数是要删除的,tail就需要置空tail->next = NULL;return newhead;
}

2. 反转一个单链表。OJ链接

思路:通过三个指针的操作,每次将当前节点反转并向前移动

struct ListNode* reverseList(struct ListNode* head) 
{	assert(head);    struct ListNode* n1, * n2, * n3;n1 = NULL;n2 = head;n3 = n2->next;while (n2){//翻转n2->next = n1;//交换n1 = n2;n2 = n3;//记录位置if(n2 != NULL)n3 = n3->next;}return n1;
}

思路:头插法

struct ListNode* reverseList(struct ListNode* head) 
{struct ListNode* cur = head;struct ListNode* newhead = NULL;while (cur){//保存cur下一个结点的位置struct ListNode* next = cur->next;//头插next = newhead;newhead = cur;//更新cur = next;}return newhead;
}

3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则 返回第二个中间结点。OJ链接

思路:快慢指针的前进方向相同,且它们步伐的「差」是恒定的,使用两个指针变量,刚开始都位于链表的第 1 个结点,一个永远一次只走 1 步,一个永远一次只走 2 步,一个在前,一个在后,同时走。这样当快指针走完的时候,慢指针就来到了链表的中间位置。

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

4. 输入一个链表,输出该链表中倒数第k个结点。OJ链接

首先让快指针先行k步,然后让快慢指针每次同行一步,直到快指针指向空节点,慢指针就是倒数第K个节点。

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k)
{struct ListNode* fast = pListHead;struct ListNode* slow = pListHead;while (k--)//走k步{//链表没有k步长,那么此时倒数就是空if (fast == NULL)return NULL;fast = fast->next;}while (fast){slow = slow->next;fast = fast->next;}return slow;
}

5. 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。OJ链接

思路一:我们可以用迭代的方法来实现上述算法。当 l1 和 l2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{if (list1 == NULL)return list2;if (list2 == NULL)return list1;struct ListNode* newhead = NULL;struct ListNode* tail = NULL;while (list1 && list2){//小值给到新链表上if (list1->val < list2->val){if (tail == NULL){newhead = tail = list1;}else{tail->next = list1;tail = tail->next;}list1 = list1->next;}else{if (tail == NULL){newhead = tail = list2;}else{tail->next = list2;tail = tail->next;}list2 = list2->next;}}if (list1)tail->next = list1;if (list2)tail->next = list2;return newhead;
}

思路二:哨兵位法,创建一个带头结点的链表,尾插的时候就不需要判断链表是不是为空的尾插情况,最后再释放哨兵位即可。

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{if (list1 == NULL)return list2;if (list2 == NULL)return list1;struct ListNode* newhead = NULL;struct ListNode* tail = NULL;//哨兵位,方便尾插newhead = tail = (struct ListNode*)malloc(sizeof(struct ListNode));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 = list1;if (list2)tail->next = list2;struct ListNode* del = newhead;newhead = newhead->next;//释放哨兵位free(del);return newhead;
}

6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。OJ链接

思路:首先创建四个节点lessHead,greaterHead,lessTail,greaterTail ,遍历整个链表,比x小的尾插到lessHead为哨兵位的那个链表,比x大的尾插到greaterHead为哨兵位的那个链表,再把两个链表连接起来 ,创建一个list节点指向这个链表 ,把greaterTail->next置空,避免成环 ,释放lessHead,greaterHead,返回list 

struct ListNode* partition(struct ListNode* pHead, int x)
{struct ListNode* lessHead, * greaterHead;lessHead = (struct ListNode*)malloc(sizeof(struct ListNode));greaterHead = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* lessTail = lessHead;struct ListNode* greaterTail = greaterHead;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;}lessTail->next = greaterHead->next;//此时greaterTail->next仍然链接初始链表的结点,需要置空,否则连环greaterTail->next = NULL;struct ListNode* newhead = lessHead->next;free(lessHead);free(greaterHead);return newhead;
}

7. 链表的回文结构。OJ链接

思路:先找到链表的中间结点,再把中间结点之后的逆序,和之前的链表比较值是否相等。

struct ListNode* middleNode(struct ListNode* head)//找中间结点
{struct ListNode* fast = head;struct ListNode* slow = head;while (fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;
}
struct ListNode* reverseList(struct ListNode* head)//反转链表
{struct ListNode* cur = head;struct ListNode* newhead = NULL;while (cur){//保存cur下一个结点的位置struct ListNode* next = cur->next;//头插next = newhead;newhead = cur;//更新cur = next;}return newhead;
}
bool chkPalindrome(struct ListNode* A) //查看值是否相等
{struct ListNode* midnode = middleNode(A);struct ListNode* reversemidnode = reverseList(midnode);while (A && reversemidnode){if(A->val != reversemidnode->val){return false;}A = A->next;reversemidnode = reversemidnode->next;}return true;
}

8. 输入两个链表,找出它们的第一个公共结点。OJ链接

思路:先计算两个链表的长度,再让较长的链表走差距步abs(lenA-LenB)长度,然后再依次比较是否相等。

struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) 
{struct ListNode* curA = headA, * curB = headB;//找尾结点 - 结点总数会少一个int lenA = 1;//设置为1int lenB = 1;//设置为1while (curA->next){curA = curA->next;lenA++;}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;}//长链表走绝对值(lenA - lenB)步int count = abs(lenA - lenB);while (count--){LongList = LongList->next;}//同时向后走,相同就停下来while (LongList != ShortList){LongList = LongList->next;ShortList = ShortList->next;}return ShortList;
}

9. 给定一个链表,判断链表中是否有环。OJ链接

思路:快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行, 如果链表 环则一定会在环中相遇,否则快指针率先走到链表的末尾。

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

 为什么快指针每次走两步,慢指针走一步可以?

  • 假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚 进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。 此时,两个指针每移动一次,快指针走两次,慢指针走一次,之间的距离就缩小一步,直至最后差距为0,不会出现每次刚好是套圈的情况,因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

快指针一次走3步,走4步,...n步行吗?

10. 给定一个链表,返回链表开始入环的第一个结点。 如果链表无环,则返回 NULL。OJ链接

思路一:一个指针从链表起始位置运行,一个指针从相遇点位置绕环,每次都走一步,两个指针最终会在入口点的位置相遇

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode *fast = head,*slow = head;while(fast && fast->next){slow = slow->next;fast = fase->next->next;//相遇在环内任意一个位置if(slow == fast){struct ListNode *meet = slow;//两结点关系L = (N-1) * C + C - X;while(head != meet){head = head->next;meet = meet->next;}return meet;}}return NULL;
}​

 思路二:两个指针相遇的地方的下一个结点置空,下一个结点位置和链表头指针此时就可以转为两条链表求解公共点的问题。

struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)//相交点 
{struct ListNode* curA = headA, * curB = headB;//找尾结点 - 结点总数会少一个int lenA = 1;//设置为1int lenB = 1;//设置为1while (curA->next){curA = curA->next;lenA++;}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;}//长链表走绝对值(lenA - lenB)步int count = abs(lenA - lenB);while (count--){LongList = LongList->next;}//同时向后走,相同就停下来while (LongList != ShortList){LongList = LongList->next;ShortList = ShortList->next;}return ShortList;
}
struct ListNode *detectCycle(struct ListNode *head) {struct ListNode *fast = head,*slow = head;while(fast && fast->next){slow = slow->next;fast = fase->next->next;//相遇在环内任意一个位置if(slow == fast){struct ListNode *meet = slow;struct ListNode *newhead = meet->next;meet->next = NULL;return getIntersectionNode(head,newhead);}}return NULL;
}

11.给定一个链表,每个结点包含一个额外增加的随机指针,该指针可以指向链表中的任何结点或空结点。 要求返回这个链表的深度拷贝。OJ链接

思路:迭代 + 节点拆分

方法:

struct Node* copyRandomList(struct Node* head) {struct Node* cur =  head;while(cur){struct Node* next = cur->next;struct Node* copy = (struct Node*)malloc(sizeof(struct Node));copy->val = cur->val;//插入cur->next = copy;copy->next = next;//往后走cur = next;}cur = head;while(cur){struct Node* copy = cur->next;//置 copy randomif(cur->random == NULL)copy->random = NULL;elsecopy->random = cur->random->next;cur = copy->next;}cur = head;struct Node* copyhead = NULL,*cpoytail = NULL;while(cur){struct Node* copy = cur->next;struct Node* next = copy->next;//copy结点尾插到新链表if(cpoytail == NULL){copyhead = copytail = copy;}else{copytail->next = copy;copytail = copytail->next;}//恢复原链表cur->next = next;cur = next;}return copyhead;
}

 本章结束啦!!!

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

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

相关文章

Go:测试框架GoConvey 简介

快速开始 GoConvey是一个完全兼容官方Go Test的测试框架&#xff0c;一般来说这种第三方库都比官方的功能要强大、更加易于使用、开发效率更高&#xff0c;闲话少说&#xff0c;先看一个example&#xff1a; package utils import (. "github.com/smartystreets/goconvey…

【JVM】运行时数据区域

文章目录 说明程序计数器虚拟机栈本地方法栈Java堆方法区运行时常量池直接内存 说明 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途&#xff0c;以及创建和销毁的时间&#xff0c;有的区域随着虚拟机进程的启动而一直…

【广州华锐互动】牲畜养殖VR模拟实操系统为传统教育注入新的生命力

随着科技的不断发展&#xff0c;虚拟现实(VR)技术已经逐渐走进我们的生活。在农业领域&#xff0c;VR技术的应用也日益广泛&#xff0c;为现代农业人才培养提供了新的途径。 由广州华锐互动开发的“牲畜养殖VR模拟实操系统”引起了广泛关注&#xff0c;系统包含了鸡、猪、牛、马…

产品流程图是什么?怎么做?

产品流程图是什么&#xff1f; 产品流程图是一种图形化的表达方式&#xff0c;用于描述产品开发、制造、销售、使用等各个阶段中涉及的流程、步骤和关系。它通过图形符号、箭头、文本等元素&#xff0c;展示了产品的各个环节之间的关联和顺序&#xff0c;通常被用于可视化产…

STM32 F103C8T6学习笔记12:红外遥控—红外解码-位带操作

今日学习一下红外遥控的解码使用&#xff0c;红外遥控在日常生活必不可少&#xff0c;它的解码与使用也是学习单片机的一个小过程&#xff0c;我们将通过实践来实现它。 文章提供源码、测试工程下载、测试效果图。 目录 红外遥控原理&#xff1a; 红外遥控特点&#xff1a; …

Qt+C++串口调试接收发送数据曲线图

程序示例精选 QtC串口调试接收发送数据曲线图 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<QtC串口调试接收发送数据曲线图>>编写代码&#xff0c;代码整洁&#xff0c;规则&…

探索GreatADM:图形化部署MGR的全新体验

摘要&#xff1a; 在DBA的日常工作中&#xff0c;快速部署数据库高可用架构&#xff0c;且标准化地入网部署数据库是一项重要的基础任务。本文将介绍常见的部署MGR的方式&#xff0c;并重点介绍万里数据库的GreatADM数据库管理平台进行图形化、可视化、标准化的部署过程&#x…

vue 学习笔记 简单实验

1.代码(html) <script src"https://unpkg.com/vuenext" rel"external nofollow" ></script> <div id"counter">Counter: {{ counter }} </div> <script> const Counter {data() {return {counter: 5}} } Vue.cr…

二、pikachu之SQL注入(2)

文章目录 1、delete注入2、http header注入3、布尔盲注4、时间盲注 4、宽字节注入 1、delete注入 &#xff08;1&#xff09;寻找传参页面&#xff0c;在删除留言的时候&#xff0c;发现是get传参&#xff1b; &#xff08;2&#xff09;判断是否存在注入点&#xff0c;命令&…

Shell语法揭秘:深入探讨常见Linux Shell之间的语法转换

深入探讨常见Linux Shell之间的语法转换 一、引言二、Linux常用Shell&#xff1a;Bash、Zsh、Ksh、Csh、Tcsh和Fish的简介2.1、Bash、Zsh、Ksh、Csh、Tcsh和Fish的特点和用途2.2、语法差异是常见Shell之间的主要区别 三、变量和环境设置的语法差异3.1、变量定义和使用的不同语法…

Redis——set类型详解

概要 Set&#xff08;集合&#xff09;&#xff0c;将一些有关联的数据放到一起&#xff0c;集合中的元素是无序的&#xff0c;并且集合中的元素是不能重复的 之前介绍的list就是有序的&#xff0c;对于列表来说[1, 2, 3] 和 [2, 1, 3]是两个不同的列表&#xff0c;而对于集合…

GraphScope,开源图数据分析引擎的领航者

文章首发地址 GraphScope是一个开源的大规模图数据分析引擎&#xff0c;由Aliyun、阿里巴巴集团和华为公司共同开发。GraphScope旨在为大规模图数据处理和分析提供高性能、高效率的解决方案。 Github地址&#xff1a; https://github.com/alibaba/GraphScope GraphScope 的重…

开发第一个gPRC的开发

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

网络综合布线实训室方案(2023版)

综合布线实训室概述 随着智慧城市的蓬勃发展,人工智能、物联网、云计算、大数据等新兴行业也随之崛起,网络布线系统作为现代智慧城市、智慧社区、智能建筑、智能家居、智能工厂和现代服务业的基础设施和神经网络,发挥着重要作用。实践表明,网络系统故障的70%发生在布线系统,直接…

苹果手机桌面APP带云图标有个箭头,过一段时间经常要下载才能使用APP

环境&#xff1a; IPhone 11 IOS13.0 问题描述&#xff1a; 苹果手机桌面APP带云图标有个箭头&#xff0c;过一段时间经常要下载才能使用APP 解决方案&#xff1a; 1.打开设置&#xff0c;往下找到iTunes Store与App Store 2.找到下面卸载未使用的APP 关闭按钮

最优的家电设备交互方式是什么?详解家电设备交互的演进之旅

家电&#xff0c;在人们的日常生活中扮演着不可或缺的角色&#xff0c;也是提升人们幸福感的重要组成部分&#xff0c;那你了解家电的发展史吗&#xff1f; 70年代 结婚流行“四大件”&#xff1a;手表、自行车、缝纫机&#xff0c;收音机&#xff0c;合成“三转一响”。 80年…

问题描述:在Windows下没有预装ImageMagick工具

问题描述:在Windows下没有预装ImageMagick工具 # WInR输入cmd回车进入命令行,执行以下命令查看版本信息 magick --version没有预装ImageMagick工具 解决方案&#xff1a;下载安装ImageMagick 官网下载:ImageMagick-7.1.1-15-Q16-x64-dll.exe 下载之后&#xff0c;一路下一步…

MySQL表的约束

MySQL表的约束 约束的概念空属性默认值列描述zerofill主键自增长唯一键外键 约束的概念 在正式谈MySQL表的约束之前&#xff0c;我们先来简单理解一下约束这个概念; 约束&#xff1a;意思是指带有束缚、限制、管束等意思&#xff1b; 大白话就是说:规定了那些事情你不能干&…

如何大幅提高遥感影像分辨率(Python+MATLAB)

前言&#xff1a; 算法&#xff1a;NSCT算法&#xff08;非下采样变换&#xff09; 数据&#xff1a;Landsat8 OLI 遥感图像数据 编程平台&#xff1a;MATLABPython 论文参考&#xff1a;毛克.一种快速的全色和多光谱图像融合算法[J].测绘科学,2016,41(01):151-15398.DOI:10.1…

k8s deployment创建pod流程图

参考 k8s 创建pod和deployment的流程 - SoulChild随笔记