单链表的经典oj题(1)

前言

这次博客将要以图解的形式,把单链表的经典题目,讲解,绝对是干货,来吧兄弟萌

第一题

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

题目链接

203. 移除链表元素 - 力扣(LeetCode)

直白的思路

这个题目完全可以无脑解决,看嘛,我们可以直接再重新构建一个链表,把不等于val值的结点

尾插起来不就好了嘛

好吧这个也让大家看看代码,我们以上面例子为例

这个代码有点长

#include<stdio.h>
#include<stdlib.h>
struct SListNode {int val;struct SListNode* next;
};
//创建节点
struct SListNode* Buynewnode(int input)
{struct SListNode* newnode = (struct SListNode*)malloc(sizeof(struct SListNode));newnode->next = NULL;newnode->val = input;return newnode;
}
int main()
{//1->2->6->3->4->5->6//构建链表struct SListNode* head = Buynewnode(1);head->next = Buynewnode(2);head->next->next = Buynewnode(6);head->next->next->next=Buynewnode(3);struct  SListNode* head4 = head->next->next->next;head4->next=Buynewnode(4);head4->next->next= Buynewnode(5);head4->next->next->next=Buynewnode(6);int val = 6;//遍历链表struct SListNode* newtail = NULL;struct SListNode* newhead = NULL;while (head){if (head->val!= val){if (newtail == NULL){newtail=newhead = Buynewnode(head->val);}else{newtail->next = Buynewnode(head->val);newtail = newtail->next;}}head = head->next;}while (newhead){printf("%d ", newhead->val);newhead = newhead->next;}return 0;
}

看看结果

是不是对上了,当然我们这里是自己实现的,所以代码量就多了些

改进思路:双指针+哨兵位节点

我们可不可以不构建,在原有的链表上改变呢

可以

通过前后指针可以抵达 前后中三个节点,如果要删除一个结点就把中间的结点删除

让前节点连接后节点

看图吧

ok

再次看看代码

struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode*phead=(struct ListNode*)malloc(sizeof(struct ListNode));phead->next=head;struct ListNode*cur=head;struct ListNode*prev=phead;while(cur){if(cur->val==val){struct ListNode*temp=cur->next;free(cur);cur=temp;prev->next=cur;}else{prev=cur;cur=cur->next;}}return phead->next;
}

这里直接用一个函数,来表示好了,主要优化空间复杂

第二题

反转链表

看看题目吧

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

206. 反转链表 - 力扣(LeetCode)

有没有想到暴力的解法呢

其实就是我们仍然可以重新构建一个链表,遍历旧的链表,在用头插的方式,刚好反转了链表对吧

1->2->3->4->5

第一次头插1 第二次头插 2->1 第三次头插 3->2->1 第四次头插 4->3->2->1 第五次头插

5->4->3->2->1

对吧

看代码就好了,代码以上面为例子

#include<stdio.h>
#include<stdlib.h>
struct SListNode {int val;struct SListNode* next;
};
struct SListNode* Buynewnode(int input)
{struct SListNode* newnode = (struct SListNode*)malloc(sizeof(struct SListNode));newnode->next = NULL;newnode->val = input;return newnode;
}
int main()
{//构建链表struct SListNode* head = Buynewnode(1);head->next = Buynewnode(2);head->next->next = Buynewnode(3);head->next->next->next = Buynewnode(4);head->next->next->next->next = Buynewnode(5);//遍历链表,并且头插struct SListNode* newhead = NULL;while (head){if (newhead == NULL){newhead = Buynewnode(head->val);}else{struct SListNode* newnode = Buynewnode(head->val);newnode->next = newhead;newhead = newnode;}head = head->next;}while (newhead){printf("%d ", newhead->val);newhead = newhead->next;}return 0;
}

这里的时间复杂度还是o(n)但是多了空间复杂(N)

我们来看看,优化方案

双指针法

思路

第一个指针叫做 prev=NULL;第二个指针叫做 cur=head;

首先一个指针在最左侧此时为NULL 另一个指针在链表第一个元素 

首先记录第二个指针的next    temp=cur->next;

再让第二个指针指向第一个指针之后     cur->next=prev;

第一个指针继承第二个指针的值,第二个指针等于它的next  prev=next;cur=cur->next;

本质的思路就是让他们的指向相反,同时就完成了反转,红色部分为核心代码

当然,整个反转链表是一个循环,结束条件就是cur为null时,因为在它为空前

它把最后一个节点个反转了

但是要注意一点,最后我们的头结点就是prev了

看代码吧

注意这里的代码是没有将自定义函数包含,当然,看了前面的,应该就可以理解

int main()
{//构建链表struct SListNode* head = Buynewnode(1);head->next = Buynewnode(2);head->next->next = Buynewnode(3);head->next->next->next = Buynewnode(4);head->next->next->next->next = Buynewnode(5);//遍历链表,并且头插struct SListNode* prev = NULL;struct SListNode* cur = head;while (cur){//构建临时变量的原因是:cur一旦改变方向就无法找到下一个,所以记录下一个struct SListNode* temp = cur->next;cur->next = prev;prev = cur;cur = temp;}while (prev){printf("%d ", prev->val);prev = prev->next;}return 0;
}

我们看看结果吧

OK

看第三题

第三题

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 

示例 2:

输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

提示:

  • 链表的结点数范围是 [1, 100]
  • 1 <= Node.val <= 100

这个题目更偏向于理解,怎么说呢其实有两种情况

一种是链表长度是奇数,另一种链表长度是偶数

奇数中间节点在中间

偶数的话在偏右边 

刚好对应两例子中的两种请况

主要的思路为快慢指针

还是画图吧

当然,这里仍然是要循环 结束条件有两个,一个是fast==NULL 另一个是fast->next==NULL

ok看代码吧

int main()
{//构造链表struct SListNode* head = Buynewnode(1);head->next = Buynewnode(2);head->next->next = Buynewnode(3);head->next->next->next = Buynewnode(4);head->next->next->next->next = Buynewnode(5);struct SListNode* slow = head;struct SListNode* fast = head;while (fast && fast->next){slow = slow->next;fast = fast->next->next;}printf("%d ", slow->val);return 0;
}

OK,如果理解,其实没有太大的问题

第四题

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值

注意:本题相对原题稍作改动

示例:

输入: 1->2->3->4->5 和 k = 2
输出: 4

说明:

给定的 k 保证是有效的

暴力思路

其实暴力思路也非常简单

我们要返回的值是int类型的值,我们完全可以把整个链表遍历一遍

把它的值存入一个数组中,然后根据k返回一个值不就行了吗?

当然这里的链表的长度不确定,所以还需要动态开辟数组

思路简单,代码也很简单

void checkmemory(int* arr, int size, int capacity)
{if (size == capacity){int* temp=(int *)realloc(arr, sizeof(capacity * 2));if (temp!= NULL){arr = temp;capacity *= 2;}}
}
int main()
{//创建数组struct SListNode* head = Buynewnode(1);head->next = Buynewnode(2);head->next->next = Buynewnode(3);head->next->next->next = Buynewnode(4);head->next->next->next->next = Buynewnode(5);int k = 2;int* arr=(int *)malloc(sizeof(int)*3);int size = 0;int capacity = 3;while (head){checkmemory(arr,size,capacity);arr[size++] = head->val;head = head->next;}printf("%d ", arr[size - k]);return 0;
}

这里仍然是空间复杂度高了

继续看优化吧

此次优化的思路来自于数学

相对位置

他不是要找倒数第k和元素吗

说明倒数第k个元素,与最后一个元素的下一个,也就是空指针相差了k个元素

比如

1->2->3->4->5->6->null

k=2,也就是5刚好与null相差2

那么反过来想,先让一个front指针走k步

然后让第二个back指针,与front指针一次走一步

那么当front指针走到NULL时,back指针与他相差k步

刚好就是倒数第k个元素

OK

这样解释应该非常清楚

看代码

//返回倒数第k个节点
int main()
{//创建数组struct SListNode* head = Buynewnode(1);head->next = Buynewnode(2);head->next->next = Buynewnode(3);head->next->next->next = Buynewnode(4);head->next->next->next->next = Buynewnode(5);int k = 2;struct SListNode* front=head;struct SListNode* back=head;while (k--){front = front->next;}while (front){front = front->next;back = back->next;}printf("%d ", back->val);return 0;
}

这样,就可以解决问题

总结

今天就写到这里吧,四题虽然少但是思路确是很好

希望有所帮助

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

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

相关文章

USB HID报告描述符学习

参考资料 HID 报告描述符 (qq.com)https://mp.weixin.qq.com/s?__bizMzU1ODI3MzQ1MA&mid2247485748&idx1&sn112bd8014eb96b03308b3b808549e8d4&chksmfc284ff1cb5fc6e770c2d2ece46c17bf2529901b45a357938978fa62163723556ad497b05c47&cur_album_id3340417…

三、VLAN间路由(三层交换)

VLAN间路由可以通过二层交换机配合路由器来实现&#xff0c;也可以通过三层交换机来实现。 目录 1.单臂路由 2.通过三层交换机实现不同vlan的互访 1.单臂路由 注&#xff1a; 1.三层接口不能正确识别带vlan tag的数据帧 2.所有子接口与主接口共享MAC地址 命令 int g0/0/0.1…

试用了三个Ai音乐工具,我的偶像河图要完蛋了

试了三个生成音乐的ai工具&#xff0c;分别是爆火的suno,后期新秀udio&#xff0c;还有我们国内的天工。 先说感受&#xff0c;suno和天工我觉得稍微靠前&#xff0c;udio可能我的配置风格有问题&#xff0c;啪啪啪连选了好几个风格&#xff0c;生成的东西有点怪。 我随手写了…

语音识别的基本概念

语音识别的基本概念​​​​​​​ ​​​​​​​ 言语是一种复杂的现象。人们很少了解它是如何产生和感知的。天真的想法常常是语音是由单词构成的&#xff0c;而每个单词又由音素组成。不幸的是&#xff0c;现实却大不相同。语音是一个动态过程&#xff0c;没有明确区分的…

linux学习:线程安全(信号量+互斥锁读写锁+条件变量+可重入函数)

目录 信号量 有名信号量 步骤 api 创建、打开一个POSIX有名信号量 对 POSIX 有名信号量进行 P、V 操作 关闭、删除 POSIX 有名信号量 例子 无名信号量 步骤 api 初始化、销毁 POSIX 无名信号量 互斥锁读写锁 例子 两条线程 使用互斥锁来互斥地访问标准输出 在加锁…

1.认识USB协议

目录 前言 在嵌入式场景的具体体现 USB通信协议 总结 前言 在这之前&#xff0c;我们需要认识USB是什么东西&#xff0c;它是一种通信协议&#xff0c;协议只是规定数据的&#xff0c;在物理层面上&#xff0c;它可以有多种表现形式。在我们日常生活中也非常常见&#xff0…

FebHost:什么是挪威.no域名,如何注册?

挪威国家域名介绍 挪威是一个位于北欧的国家&#xff0c;北面和西面是大西洋和北海&#xff0c;东面和南面则与瑞典、芬兰接壤。挪威是一个高度发达的经济体&#xff0c;其政府在经济管理和可持续发展方面也取得了很多成就。挪威的人均GDP在世界范围内排名非常靠前&#xff0c…

【Unity】 使用代码分析(Roslyn Analyzers)实现自动代码审查(Code Review)

索引 Roslyn AnalyzersCode Review自动 Code Review 案例1.public、internal权限的字段建议以大写字母开头。2.private、protected权限的字段建议以下划线小写字母开头。3.不建议直接继承 MonoBehaviour&#xff0c;建议继承至 HTBehaviour。4.不建议使用 Input 判断输入或获取…

命令执行。

命令执行 在该项目的readme中&#xff0c;描述了怎么去调用的flink 通过java原生的runtime来调用flink&#xff0c;下一步就是去看看具体的调用过程了&#xff0c;是否存在可控的参数 找到具体提交命令的类方法CommandRpcClinetAdapterImpl#submitJob() 这里要确定command&am…

C++-6

使用模板类&#xff0c;实现顺序栈。 #include <iostream>using namespace std; template <typename T> class Seqlite {T data[30];int len0; public:void head_inst(T date);void head_dele();void show(); }; template <typename T> …

Phi-3-mini-4k-instruct 的功能测试

Model card 介绍 Phi-3-Mini-4K-Instruct 是一个 3.8B 参数、轻量级、最先进的开放模型&#xff0c;使用 Phi-3 数据集进行训练&#xff0c;其中包括合成数据和经过过滤的公开可用网站数据&#xff0c;重点是 高品质和推理密集的属性。 该型号属于 Phi-3 系列&#xff0c;Mini…

Django框架之ORM操作

一、选择数据库 1、默认数据库 Django默认的数据库是sqlite3数据库 DATABASES {default: {ENGINE: django.db.backends.sqlite3,NAME: BASE_DIR / db.sqlite3,} }2、指定数据库 修改连接到MySQL数据库 DATABASES {default: {ENGINE: django.db.backends.mysql,# 数据库名…

一、安装Redis并运行

Windows安装Redis 1.打开网址下载 下载地址&#xff1a;https://github.com/tporadowski/redis/releases。 Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择 我选择的是 然后一步步安装 可以参考&#xff1a;https://blog.csdn.net/zbx931197485/article/d…

李廉洋:4.29黄金原油最新走势分析,做单必看策略,

传统定价框架下&#xff0c;黄金兼具货币、商品和金融三重属性&#xff0c;对应货币、抗通胀和避险价值&#xff0c;因此通常与美元、美债利率反向变动。但近期这一定价规律“失灵”了&#xff0c;黄金、利率和美元同涨。三者同涨后&#xff0c;一个月后续转为下跌的频率超过一…

JS - 以工厂模式和原型模式方式建造对象、JS的垃级回收机制、数组的使用

创建对象的方式 使用工厂方法来建造对象 在JS中我们可以通过以下方式进行创建对象&#xff1a; var obj {name:"孙悟空",age:18,gender:"男",sayName:function(){alert(this.name);}};var obj2 {name:"猪八戒",age:28,gender:"男",…

【Java EE】总结12种锁策略以及synchronized的实现原理

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

基于yolov5实时实例分割

是一个结合了最新技术进展&#xff08;State-of-the-Art, SOTA&#xff09;的实时实例分割项目&#xff0c;基于著名的YOLOv5目标检测架构&#xff0c;并对其进行扩展以实现对图像中每个对象实例的精确像素级分割。以下是该项目的中文介绍&#xff1a; YOLOv5&#xff1a; YOL…

Java后端利用百度地图全球逆地理编码,获取地址

声明&#xff1a;本人是在实习项目的时候遇到的问题 一.使用Api分为四步骤全球逆地理编码 rgc 反geo检索 | 百度地图API SDK 步骤1,2自行完成 接下来去获取AK 二.申请AK 登录百度账号 点击创建应用&#xff0c;选择自己想用的服务&#xff0c;我只单选了逆地理编码&#xff…

go语言实现简单认证样例

目录 1、代码实现样例 2、postman调用 1、代码实现样例 package mainimport ("net/http""strings""github.com/dgrijalva/jwt-go""github.com/gin-gonic/gin" )var (// 密钥&#xff0c;用于验证 JWT 令牌signingKey []byte("…

【1762】java校园单车投放系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java校园单车投放管理系统是一套完善的java web信息管理系统 采用serlvetdaobean&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S 模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#…