链表OJ(LeetCode)

news2025/3/13 18:00:15

文章目录

  • 1.移除链表元素
  • 2.反转链表
  • 3.链表的中间结点
  • 4.倒数第k个结点
  • 5.合并两个有序链表
  • 6.链表分割
  • 7.链表的回文结构
  • 8.相交链表
  • 9.环形链表
  • 10.环形链表Ⅱ
    • 1.常规思路
    • 2.新型思路【无码】

1.移除链表元素

在这里插入图片描述
法一:遍历删除

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* rmele(struct ListNode* head, int val)
{
	struct ListNode* prv = NULL;
	struct ListNode* cp = head;
	while (cp)
	{
		if (cp->val == val)
		{
			if (cp == head) //头删
			{
				//head自动指向cp的下一结点
				head = cp->next;
				//删除目标结点
				free(cp);
				//更新cp
				cp = head;

			}
			else
			{
				//prv连接cp的next结点
				prv->next = cp->next;
				//删除目标值
				free(cp);
				//更新cp
				cp = prv->next;
			}
			
		}
		else //不是继续遍历
		{
			prv = cp;
			cp = cp->next;
		}
	}
	return head;
}

法二:循环尾插

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* rmele(struct ListNode* head, int n)
{
	struct ListNode* tail = NULL;
	struct ListNode* cp = head;
	head = NULL; 
	//不置空 若遇到全是目标值的链表 
	//删除后--head应指向NULL--不置空head指向原头结点
	while (cp)
	{
		if (cp->val == n) //是目标值删除
		{
			//obj指向要被删除的目标值
			struct ListNode* obj = cp;
			//cp后移
			cp = cp->next;
			//删除目标值
			free(obj);	
		}
		else              //非目标值尾插
		{
			if (tail == NULL) //尾插首值
			{
				head = cp; //更新head 指向新的头结点
				tail = cp; //更新tail 指向新的尾结点
			}
			else              //尾插非首值
			{
				//tail连接非目标值
				tail->next = cp;
				//更新tail 
				tail = cp; //更新tail 指向新的尾结点
			}
			//cp后移
			cp = cp->next;
		}
	}
	//遍历结束 尾结点的指针域须被置空
	//若遇到空链表 tail初值为空 无法访问next
	if (tail != NULL)
		tail->next = NULL;

	return head;
}

法三:带哨兵位的头结点

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* rmele(struct ListNode* head, int n)
{
	struct ListNode* tail = NULL;
	struct ListNode* cp = head;
	head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
	tail->next = NULL;
	while (cp)
	{
		if (cp->val == n) //是目标值删除
		{
			//obj指向要被删除的目标值
			struct ListNode* obj = cp;
			//cp后移
			cp = cp->next;
			//删除目标值
			free(obj);
		}
		else              //非目标值尾插
		{
			//tail连接非目标值
			tail->next = cp;
			//更新tail 
			tail = cp; //更新tail 指向新的尾结点
			//cp后移
			cp = cp->next;
		}
		//尾插后将指针域置空
		tail->next = NULL;
		//sentinel:哨兵
		struct ListNode* sp = head;
		//更新head 指向非哨兵位的头结点
		head = head->next;
		//销毁哨兵位
		free(sp);

		return head;
	}
}

2.反转链表

在这里插入图片描述
法一:循环头插
在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
};
//nh:newhead 
//cp:pointer to current 
//pnext:pointer to next
struct ListNode* reverseList(struct ListNode* head) 
{
	struct ListNode* nh = NULL;
	struct ListNode* cp = head;
	while (cp)
	{
		//pn永远指向cp的下一个结点
		struct ListNode* pnext = cp->next;
		//nh指向上一个结点-->初始为空
		cp->next = nh; //cp的指针域存储上一个结点空间地址 ==》cp连接nh(上一个结点)
		//nh指向更新 指向现结点空间地址
		nh = cp;
		//cp后移
		cp = pnext;
	}
	return nh;
}

法二:改变指针指向
在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
};

struct ListNode* reverseList(struct ListNode* head)
{
	if (head == NULL)
		return NULL;
	struct ListNode* prv, * cp, * pn;
	prv = NULL;
	cp = head;
	pn = cp->next;
	while (cp)
	{
		//cp连接前结点
		cp->next = prv;
		//前结点指针后移
		prv = cp;
		//现结点指针后移
		cp = pn;
		//原pn非空
		if (pn != NULL)
		{
			pn = pn->next;
		}
	}
	return prv;
}

3.链表的中间结点

在这里插入图片描述
在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* middleNode(struct ListNode* head)
{
	struct ListNode* s,* f;
	s = f = head;
	while (f && f->next)
	{
		s = s -> next;
		f = f -> next -> next;
	}
	return s;
}

4.倒数第k个结点

在这里插入图片描述
在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k)
{
	struct ListNode* s, * f;
	s = f = pListHead;
	//f先前进k步
	while (k--)
	{	
		if (f != NULL)     //防止输入的值k > 链表长度
			f = f->next;   //即f还未走完k步 链表已结束
		else
			return NULL;
	}
	while (f)
	{
		s = s->next;
		f = f->next;
	}
	return s;
}

5.合并两个有序链表

在这里插入图片描述
法一:归并插入

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{
	if (list1 == NULL)
		return list2;
	if (list2 == NULL)
		return list1;

	struct ListNode* head, * tail;
	head = tail = NULL;

	while (list1 && list2)
	{
		if (list1->val < list2->val)
		{
			if (tail == NULL)
			{
				//头插--直接指向obj
				head = tail = list1;
			}
			else
			{
				tail->next = list1;
				//后移
				tail = tail->next;
			}
			//后移
			list1 = list1->next;
		}
		else
		{
			if (tail == NULL)
			{
				head = tail = list2;
			}
			else
			{
				tail->next = list2;
				tail = tail->next;
			}
			//后移
			list2 = list2->next;
		}
	}

	if (list1)
		tail->next = list1;
	if (list2)
		tail->next = list2;
	//新链表头结点
	return head;
}

法二:带哨兵位的头结点

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) 
{
	struct ListNode* head, * tail;

	//哨兵位
	head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
	tail->next = NULL;

	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* realhead = head->next;
	free(head);
	return realhead;
}

6.链表分割

在这里插入图片描述
在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
	ListNode(int x)
		:val(x)
		,next(nullptr)
	{

	}
};
class Partition
{
public:
	ListNode* partition(ListNode* pHead, int x)
	{
		//创建哨兵位
		struct ListNode* big_head, * big_tail, * less_head, * less_tail;

		big_head  = big_tail  = (struct ListNode*)malloc(sizeof(struct ListNode));
		less_head = less_tail = (struct ListNode*)malloc(sizeof(struct ListNode));

		big_tail->next  = nullptr;
		less_tail->next = nullptr;

		//遍历
		struct ListNode* cp = pHead;
		while (cp)
		{
			if (cp->val < x)
			{
				less_tail->next = cp;
				less_tail = less_tail->next;
			}
			else
			{
				big_tail->next = cp;
				big_tail = big_tail->next;
			}

			cp = cp->next;
		}
		//连接两段链表
		less_tail->next = big_head->next;
		//注意尾结点指针域置空
		big_tail->next = nullptr;

		struct ListNode* newhead = less_head->next;
		free(big_head);
		free(less_head);
		return newhead;
	}
};

7.链表的回文结构

在这里插入图片描述
在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
};
//寻找中间结点
struct ListNode* middleNode(struct ListNode* head)
{
	struct ListNode* s, * f;
	s = f = head;
	while (f && f->next)
	{
		s = s->next;
		f = f->next->next;
	}
	return s;
}
//后半段逆置
struct ListNode* reverseList(struct ListNode* head)
{
	struct ListNode* nh = NULL;
	struct ListNode* cp = head;
	while (cp)
	{
		//pn永远指向cp的下一个结点
		struct ListNode* pnext = cp->next;

		//nh指向上一个结点-->初始为空
		cp->next = nh; //cp的指针域存储上一个结点空间地址 ==》cp连接nh(上一个结点)
		
		//nh指向更新 指向现结点空间地址
		nh = cp;
		
		//cp后移
		cp = pnext;
	}
	return nh;
}
//判断回文
bool isPalindrome(struct ListNode* head) 
{
	struct ListNode* mid = middleNode(head);
	struct ListNode* rhead = reverseList(mid);
	while (head && rhead)
	{
		if (head->val != rhead->val)
		{
			return false;
		}
		else
		{
			head = head->next;
			rhead = rhead->next;
		}
	}
	return true;
}

8.相交链表

在这里插入图片描述
在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
	if (headA == NULL || headB == NULL)
		return NULL;

	struct ListNode* cpA = headA, * cpB = headB;
	//求链表长度
	int lenA = 1, lenB = 1;
	while (cpA->next)
	{
		cpA = cpA->next;
		lenA++;
	}
	while (cpB->next)
	{
		cpB = cpB->next;
		lenB++;
	}
	//若链表相交 尾结点空间地址定相同
	if (cpA != cpB)
		return NULL;

	//定位长短链表
	struct ListNode* S_list = headA, * L_list = headB;
	if (lenA > lenB)
	{
		S_list = headB;
		L_list = headA;
	}
	//求长度差
	int gap = abs(lenA - lenB);
	//长链表前进gap步
	while (gap--)
	{
		L_list = L_list->next;
	}
	while (S_list != L_list)
	{
		S_list = S_list->next;
		L_list = L_list->next;
	}
	return S_list;
}

9.环形链表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
};
bool has_cycle(struct ListNode* head) 
{
	struct ListNode* f = head, * s = head;
	while (f && f->next)
	{
		s = s->next;
		f = f -> next->next;
		if (s == f)
			return true;
	}
	return false;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
n是偶数能追上
n是奇数 C-1是偶数能追上
n是奇数 C-1是奇数追不上

10.环形链表Ⅱ

在这里插入图片描述

1.常规思路

slow进环后在一圈内一定会被fast追上:slow进环后 fast一定在slow前面 二者之间最大距离为一圈 slow走1圈 fast会走2圈 超出的这一圈绝对会碰到slow ==》 fast最多走2圈就会追上slow【fast比slow每次多走一步的前提下】

在这里插入图片描述

struct ListNode
{
	int val;
	struct ListNode* next;
};
struct ListNode* detectCycle(struct ListNode* head) 
{
	struct ListNode* s, * f;
	s = f = head;
	//若f 、 f->next二者有一为空 == 定不存在环
	while (f && f->next)
	{
		//s走1步 f走2步
		s = s->next;
		f = f -> next->next;
		//s == f :定有环
		if (s == f)
		{
			struct ListNode* meet = s;
			while (meet != head)
			{
				meet = meet->next;
				head = head -> next;
			}
			//相等即二者相遇 相遇点即为交点
			return meet;
		}
	}
	return NULL;
}

2.新型思路【无码】

在这里插入图片描述

问题变成了:newhead的链表和head的链表的寻找交点的问题

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

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

相关文章

采集极验4滑块验证码图片数据

在网络安全领域&#xff0c;验证码是一种常见的用于验证用户身份或防止恶意机器人攻击的技术。而极验4滑块验证码作为一种广泛应用的验证码形式&#xff0c;其具有较高的安全性和防御能力。本文将以获取极验4滑块验证码图片数据为主题&#xff0c;介绍相关技术和方法。 一、极…

【Jenkins入门到实战】忽如一夜春风来,千树万树梨花开

自动化运维之Jenkins 前提条件&#xff1a;安装好jdk &#xff08;版本要求11-17&#xff09;并配置好环境变量 一、Jenkins 1、Jenkins是什么 Jenkins是一个开源的持续集成服务&#xff0c;用于实施软件开发和发布流程。它帮助软件开发和运维团队在构建、测试和部署软件上实…

cesium的使用

cesium的使用 cesium的使用创建一个vue项目 vuevitecesium参数的使用常用点位标记删除动态渲染路线借助truf.js的算法进行渲染地块的实现topojson cesium的使用 1.下载或者安装cesium的插件 官方文档 下载下来后创建文件夹整个包引入 2.生成token 新的包应该有默认token如果没…

前端学习记录~2023.7.10~CSS杂记 Day5

前言一、样式化表格1、一个典型的 HTML 表格2、进行样式化&#xff08;1&#xff09;间距和布局&#xff08;2&#xff09;简单地排版&#xff08;3&#xff09;图形和颜色&#xff08;4&#xff09;图案&#xff08;5&#xff09;样式化标题 最终效果如下 ![在这里插入图片描述…

【Spring Cloud Alibaba】Nacos的服务注册和发现(discovery)的使用

【Spring Cloud Alibaba】系列文章 标题链接【Spring Cloud Alibaba】Nacos的安装与介绍以及Nacos集群的安装https://masiyi.blog.csdn.net/article/details/129530053【Spring Cloud Alibaba】Nacos config的使用和高阶用法https://masiyi.blog.csdn.net/article/details/129…

LabVIEW通过嘴唇图像识别为残疾人士开发文本输入系统

LabVIEW通过嘴唇图像识别为残疾人士开发文本输入系统 近年来&#xff0c;计算机已经成为现代人日常生活中的一种信息器具。人们可以使用计算机来处理复杂的文件&#xff0c;获取新信息并在线购物等。但是&#xff0c;上面讲的使用电脑的所有好处对普通人来说都很方便&#xff…

React05-样式隔离

一、样式隔离方案 css 的样式是全局样式&#xff0c;在书写react组件时&#xff0c;如果写了相同的样式类名&#xff0c;很容易造成样式污染。 在 vue 中&#xff0c;vue 官方提供了样式隔离方法&#xff0c;在组件代码中的 style 标签中加入 scoped&#xff0c;可以让这部分…

Python案例分析|使用Python图像处理库Pillow处理图像文件

本案例通过使用Python图像处理库Pillow&#xff0c;帮助大家进一步了解Python的基本概念&#xff1a;模块、对象、方法和函数的使用 使用Python语言解决实际问题时&#xff0c;往往需要使用由第三方开发的开源Python软件库。 本案例使用图像处理库Pillow中的模块、对象来处理…

Java中的JDBC编程(数据库系列6)

目录 前言&#xff1a; 1.什么是Java的JDBC编程 2.JDBC的数据库驱动包的导入过程 3.JDBC代码的编写 3.1创建并初始化一个数据源 3.2和数据库服务器建立连接 3.3构造SQL语句 3.4执行SQL语句 3.5释放必要的资源 3.6整体代码的展示及演示 3.7代码的优化 3.8 查询操作的…

「深度学习之优化算法」(十四)麻雀搜索算法

1. 麻雀搜索算法简介 (以下描述,均不是学术用语,仅供大家快乐的阅读)   麻雀搜索算法(sparrow search algorithm)是根据麻雀觅食并逃避捕食者的行为而提出的群智能优化算法。提出时间是2020年,相关的论文和研究还比较少,有可能还有一些正在发表中,受疫情影响需要论…

关于学习过程中的小点

nfev : 函数求值次数njev : Jacobian 评估的数量nit :算法的迭代次数 permute(dims)#维度转换 torch.split #[按块大小拆分张量] Pytorch.view Pytorch中使用view()函数对张量进行重构维度&#xff0c;类似于resize()、reshape()。用法如下&#xff1a;view(参数a,参数b,...)&a…

Nacos1.4.2单机与集群的安装部署

CentOS 部署Nacos1.4.2 下载 nacos 下载链接&#xff1a;https://github.com/alibaba/nacos/tags 如何选择我们下载的 nocas 版本&#xff1f; 查看 Spring Cloud Alibaba 与 nacos 版本对应关系&#xff1a;SpringCloudAlibaba 组件对应关系说明 本项目使用 nacos 1.4.2 …

Python(十七)数据类型转换——str()函数和int()函数

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

2023年上半年:C#、Python和一些实用语言

文章目录 C#Pythonerlang和exilirfortranR语言 最近半年的开发任务主要集中在C#和Python上&#xff0c;所以博客内容也几乎围绕这两个部分&#xff0c;偶尔会穿插一些其他语言。下面就对2023年上半年的博客做一个总结。 C# 主要用C#写了一个文本阅读器&#xff0c;提供生成目…

学C的第二十八天【字符串函数和内存函数的介绍(一)】

相关代码gitee自取&#xff1a;C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第二十七天【指针的进阶&#xff08;三&#xff09;】_高高的胖子的博客-CSDN博客 前言&#xff1a; &#xff08;1&#xff09;. C语言中对于字符和字符串的处理很是频繁&…

linux驱动开发:驱动开发框架,linux内核字符设备驱动开发过程

一、驱动框架 1.Linux内核模块和字符驱动的关系 模块是Linux进行组建管理的一种方式, 结构体:对设备的管理内核需要抽象出来一个结构体来描述设备所有的共性信息写驱动需要申请一个结构体并赋值(初始化),然后注册给内核让内核统一管理 驱动:由内核统一管理,所以驱动…

NUXT3学习笔记2

1、配置Ant design Vue (两个安装方式随便选一种&#xff0c;yarn会安装的更快) npm i ant-design-vue --save yarn add ant-design-vue 2、使⽤的 Vite&#xff0c;你可以使⽤ unplugin-vue-components 来进⾏按需加载。 yarn add unplugin-vue-components --save 在nuxt.…

设计模式——享元模式

享元模式 定义 享元模式&#xff08;Flyweight Pattern&#xff09;是池技术的重要实现方式。 使用共享对象可以有效地支持大量的细粒度对象。 优缺点、应用场景 优点 可以大大减少应用程序创建对象的数量&#xff0c;降低程序内存占用。 缺点 提高了系统的复杂度&…

5分钟上手IP代理服务

一 IP代理服务 在网上找了一个性价比高的IP代理服务&#xff0c;一个IP地址1分钱。 二 API协议 调用方式为http协议&#xff0c;响应数据格式支持JSON和txt&#xff0c;都是比较常用的方式。 三 源码范例 包括一些主流的编程语言&#xff0c;一分钟上手。 我用的python比较…

【Redis应用】查看附近(五)

&#x1f697;Redis应用学习第五站~ &#x1f6a9;本文已收录至专栏&#xff1a;Redis技术学习 查看附近的XXX在我们的实际应用中非常广泛&#xff0c;能支持该功能的技术有很多&#xff0c;而在我们的Redis中主要依靠GEO数据结构来实现该功能&#xff01; 一.GEO用法引入 GE…