单链表经典oj题(2)

前言

这次将要把剩下的oj题将以图解和自己的理解把它讲解完,希望对大家有所帮助,这次的讲解也是干货

第一题

21. 合并两个有序链表 - 力扣(LeetCode)

ok这次就简单点,大家自己去看题目了

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

暴力思路

想想看不考虑空间和时间的消耗,什么代码最容易想

两个链表,可不可以直接把两个链表的值放在一个数组中

然后再排序,当然这里的链表大小是有序的,放在数组中时

可以判断大小,从而不用去排序

再根据数组自行去malloc一个链表,是不是非常暴力的思路

这个暴力代码其实也很重要,至少是算法小白入门的绝招

#include<stdio.h>
#include<stdlib.h>
typedef struct SlistNode {struct SlistNode* next;int val;
}SLNode,*SL;
SLNode* Buyslistnode(int data)
{SL newnode = (SL)malloc(sizeof(SLNode));newnode->next = NULL;newnode->val = data;return newnode;
}
SL initlist1()
{SL list1 = (SL)malloc(sizeof(SLNode));list1->val = 1;list1->next = Buyslistnode(2);list1->next->next = Buyslistnode(4);return list1;
}
SL initlist2()
{SL list2 = (SL)malloc(sizeof(SLNode));list2->val = 1;list2->next = Buyslistnode(3);list2->next->next = Buyslistnode(4);return list2;
}
int cmp(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}
void text1()
{//我们这里直接考虑list1与list2都不是空链表的情况//其实其他的情况可以通过if判断排除//初始化题目//list1   1->2->4//list2   1->3->4SL list1 = initlist1();SL list2 = initlist2();//题目中链表的结点数是0~50//所以直接可以用静态数组int newarr[110];int size = 0;while (list1){newarr[size++] = list1->val;list1 = list1->next;}while (list2){newarr[size++] = list2->val;list2 = list2->next;}qsort(newarr, size, sizeof(int), cmp);SL phead = (SL)malloc(sizeof(SLNode));SL cur = phead;for (int i = 0; i < size; i++){cur->next = Buyslistnode(newarr[i]);cur = cur->next;}//至此已经完成//打印看结果吧cur = phead->next;while (cur){printf("%d ", cur->val);cur = cur->next;}
}
int main()
{text1();return 0;
}

那么看结果

OK接下来看看优化的思路 头结点+双头插

对于这个例子

我们一第二条链表为基础对他进行插入操作

我们使用两个指针,分别指向两条链表的第一个位置cur1 cur2

如果第一个链表的值小于第二个链表的值那么尾插到此时第二个链表指针的前面

cur1->val<=cur2->val      

并且让第一个指针cur1=cur1->next;

当然这里只是大题思路不是代码

如果大于 cur1->val>cur2->val   

那么让cur2=cur2->next

在进行操作的时候,我们为了避免在第一个位置插入 ,从而加入了头指针

OK,看代码呗

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if(list1==NULL&&list2==NULL)return list1;else if(list1!=NULL&&list2==NULL)return list1;else if(list1==NULL&&list2!=NULL)return list2;struct ListNode*p1=list1;struct ListNode*p2=list2;struct ListNode*p2head=(struct ListNode*)malloc(sizeof(struct ListNode));p2head->next=p2;struct ListNode*front=p2head;while(p1&&p2){if(p1->val<=p2->val){//双指针中间插入//front->next=p1;struct ListNode*temp=p1;p1=p1->next;temp->next=p2;front=temp;}else{front=p2;p2=p2->next;}}//如果p2==null此时p1不为空,把p1接起来if(p2==NULL)front->next=p1;return p2head->next;}

 第二题

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

链表分割_牛客题霸_牛客网 (nowcoder.com)

ok

这个题目其实也可以暴力

但是

已经写了好多次暴力了,对吧

这一次可以说说思路

仍然可以使用数组,然后直接排序,不管x为多少,按从小到大的顺序,没有错

然后构建链表,这个题目就完了

挺暴力的吧

可以的

但是这个代码和之前大差不差

直接来看具体的思路

我们可以把一个链表分成两个链表,list1一个是大于等于x的,list2一个是小于x的

最后让list2连接list1

就完成任务了

思路看起来简单但是细节还是很多

我们在代码中有注释

class Partition {
public:ListNode* partition(ListNode* pHead, int x) {if(pHead==NULL&&pHead->next==NULL)return pHead;auto *head=(ListNode*)malloc(sizeof(ListNode));head->next=pHead;//头结点ListNode*front=head;ListNode*newlist=NULL;ListNode*newtail=NULL;ListNode*p=pHead;while(p){if(p->val<x){//在原有的链表上去除小于x的值ListNode*temp=p;p=p->next;temp->next=NULL;front->next=p;//对新的链表操作//小于x的值重新连成一个链表if(newlist==NULL){newlist=newtail=temp;}else{newtail->next=temp;newtail=temp;}}else {front=p;p=p->next;  }}//不要忘了呀,新的链表有可能为空呀,哎呦,搞了个半天if(newtail==NULL)return pHead;elsenewtail->next=head->next;return newlist;}
};

这个题目思路还是不难,继续努力

第三题

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

1->2->2->1
返回:true

这个题目有难度了

所以我们可以通过画图来理解一下

思路,

我们可以找到中间的结点,把中间的结点逆置过来

然后一个指针从中间

另一个指针从开头

一直判断他们是否相等,就可以得到答案

看图呗

 OK,找中以及逆转链表之前已经有过讲解了

单链表的经典oj题(1)-CSDN博客

好吧,不懂可以去看

我们现在直接去看代码喽

 ListNode*middle(ListNode*A){ListNode*slow=A;ListNode*fast=A;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;}return slow;}ListNode* revearse(ListNode*src){ListNode* cur=src;ListNode* prev=NULL;while(cur){ListNode* temp=cur->next;cur->next=prev;prev=cur;cur=temp;}return prev;}bool chkPalindrome(ListNode* A) {// write code hereListNode*cur=middle(A);ListNode* tail=revearse(cur);while(A&&tail){if(tail->val!=A->val)return false;tail=tail->next;A=A->next;}return true;}

第四题

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 

题目在这里

160. 相交链表 - 力扣(LeetCode)

OK

思路

 首先要判断他们是否是有相交节点

OK可以让他们走到最后一个节点

如果他们的最后一个节点相等,那他们就有相交节点,那么问题来了

怎么找到节点呢

要是知道两个链表的长度,再利用相对位移让他们距离相交节点的位移一样

最后让他们同时走,再判断,直到相等即可

OK

看代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode*A =headA;struct ListNode*B =headB;//这里最后一个节点没有加上,所以初始为1int sizeA=1;int sizeB=1;while(A->next){A=A->next;sizeA++;}while(B->next){B=B->next;sizeB++;}if(A!=B)return NULL;//通过假设,来简化代码//总之就是让A最长if(sizeA<sizeB){A=headB;B=headA;}else{A=headA;B=headB;}int abs=sizeA-sizeB>0?sizeA-sizeB:sizeB-sizeA;//使他们里相交点的距离相等while(abs--){A=A->next;}while(A!=B){A=A->next;B=B->next;}return B;
}

第五题 

 141. 环形链表 - 力扣(LeetCode)

题目

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点

OK

这个题目的思路很重要,我这里有两种做法

暴力求解

如果只要求求出题目,那么我们可不可以用一个数据来标明这个节点走过没有

  • -10^5 <= Node.val <= 10^5

当我们走过一个结点

直接给他加上一个10^6+10

+10是防止特殊情况,那么只要遍历一遍,走到某个节点,如果它大于

10^5证明我们走过这里,但是此时又回到了这里,此时可以判断为有环

缺点是破坏了链表

bool hasCycle(struct ListNode *head) {while(head){if(head->val>1e5)return true;else{head->val+=1e6+10;}head=head->next;}return false;
}

这种办法还是挺有意思的不是吗?

OK

来看看不改变链表的结构的写法吧

这个还是要画图理解,并且这里还是涉及到了相对位置的概念

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(slow == fast)return true;}return false;}

话不多说下一题

第六题

142. 环形链表 II - 力扣(LeetCode)

 这个题目,是上个题目的升级版

OK看题

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

思路

大家看这里就是不允许修改链表了

这该如何是好

还是画图吧

这个题目更是一个物理的模型

OK,看代码吧

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode*slow=head;struct ListNode*fast=head;struct ListNode*meet=NULL;struct ListNode*find=head;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;if(fast==slow){meet=slow;break;}}if(meet==NULL)return NULL;while(find!=meet){find=find->next;meet=meet->next;}return find;
}

总结

今天的题还是挺多的,好好练吧

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

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

相关文章

Ubuntu18.04--虚拟机配置Samba并从Windows登录

前言&#xff1a; 本文记录我自己在Windows上安装 Virtualbox &#xff0c;并在Virtualbox中安装 Ubuntu-18.04 虚拟机&#xff0c;在Ubuntu-18.04虚拟机里安装配置Smaba服务器&#xff0c;从 Windows 宿主系统上访问虚拟机共享samba目录的配置命令。 引用: N/A 正文 虚拟…

​​​【收录 Hello 算法】5.1 栈

目录 5.1 栈 5.1.1 栈的常用操作 5.1.2 栈的实现 1. 基于链表的实现 2. 基于数组的实现 5.1.3 两种实现对比 5.1.4 栈的典型应用 5.1 栈 栈&#xff08;stack&#xff09;是一种遵循先入后出逻辑的线性数据结构。 我们可以将栈类比为桌面上的一摞盘子…

Linux diff命令(比较两个文件或目录的内容差异)

文章目录 Linux diff 命令详解教程基本用法比较文件输出解释 递归比较&#xff08;-r&#xff09;示例代码 控制输出格式统一格式&#xff08;-u&#xff09;上下文格式&#xff08;-c&#xff09; 高级选项忽略所有空白差异&#xff08;-w&#xff09;仅报告文件是否不同 Linu…

SVN 合并到 Git 时有文件大于 100 M 被限制 Push

如果有文件大小大于 100M&#xff0c;GitHub 是会被限制推送到仓库中的&#xff0c;大概率情况会显示下面的错误&#xff1a; remote: Resolving deltas: 100% (3601/3601), done. remote: error: Trace: aea1f450da6f2ef7bfce457c715d0fbb9b0f6d428fdca80233aff34b601ff59b re…

RobbitMQ基本消息队列的消息发送过程

RabbitMQ: One broker to queue them all | RabbitMQ RabbitMQ官网 SpringAmqp的官方地址&#xff1a;Spring AMQP 代码示例:对着代码看应该能看明白 publisher:消息发送者的代码示例 package cn.itcast.mq.helloworld;import com.rabbitmq.client.Channel; import com.rabb…

线路和绕组中的波过程(一)

本篇为本科课程《高电压工程基础》的笔记。 本篇为这一单元的第一篇笔记。下一篇传送门。 当电路中的设备&#xff08;元件&#xff09;最大实际尺寸l大于人们所感兴趣的谐波波长 λ \lambda λ时&#xff0c;可以作为集中参数处理&#xff0c;否则就要当做分布参数处理。即&…

基于STM32移植lvgl(V8.2)(SPI接口的LCD)

目录 概述 1 认识LVGL 1.1 LVGL官网 1.2 LVGL库文件下载 2 认识SPI接口型LCD 2.1 PIN引脚定义 2.2 MCU IO与LCD PIN对应关系 3 实现LCD驱动 3.1 使用STM32Cube配置Project 3.2 STM32Cube生成工程 4 移植LVGL 4.1 准备移植文件 4.2 添加lvgl库文件到项目 4.2.1 src下…

linux fdisk 银河麒麟操作系统 v10 磁盘分区和挂载 详细教程

1查看 未加载的磁盘 fdisk -l 2 开始分区 fdisk /dev/vdb #查看分区 #新建分区和保存 3 格式化和挂载 fdisk -l mkfs.xfs /dev/vdb1 #查看uuid blkid /dev/vdb1 mkdir /data vi /etc/fstab UUID209daa-fb1c-48f2-bf5e-e63f38cb8a /data xfs defaults 0 0 #加载下 mo…

探秘未来科技:数字化无人巡检的奇妙之旅

嘿&#xff0c;朋友们&#xff01;下午茶时间到&#xff01;趁着这会儿咱们来聊一个超级炫酷的话题——数字化无人巡检。想象一下&#xff0c;那些曾经需要人工跋山涉水、风吹日晒的巡检工作&#xff0c;现在正被一群“智能小分队”悄悄接手&#xff0c;是不是觉得既神奇又方便…

Ascent DMS AE电源说明书和设备连接调试教程

Ascent DMS AE电源说明书和设备连接调试教程

彩虹聚合DNS管理系统

聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。本系统支持多用户&#xff0c;每个用户可分配不同的域名解析权限&#xff1b;支持API接口&#xff0c;支持获取域名…

FFmpeg常用API与示例(三)—— 音视频解码与编码

编解码层 1.解码 (1) 注册所有容器格式和 CODEC:av_register_all() (2) 打开文件:av_open_input_file() (3) 从文件中提取流信息:av_find_stream_info() (4) 穷举所有的流&#xff0c;查找其中种类为 CODEC_TYPE_VIDEO (5) 查找对应的解码器:avcodec_find_decoder() (6) …