DS:八大排序之堆排序、冒泡排序、快速排序

news2025/6/26 13:02:26

                                                 创作不易,友友们给个三连吧!! 

一、堆排序

堆排序已经在博主关于堆的实现过程中详细的讲过了,大家可以直接去看,很详细,这边不介绍了

DS:二叉树的顺序结构及堆的实现-CSDN博客

直接上代码:

void AdjustDown(int* a, int n, int parent)//升序要建大堆
{
	int child = parent * 2 + 1;//假设左孩子比右孩子大
	while (child < n)
	{
	//如果假设错误,就认错
		if (child + 1 < n && a[child] < a[child + 1])
			child++;
		//如果孩子大于父亲,交换
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			//交换完后,让原来的孩子变成父亲,然后再去找新的孩子
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}

void HeapSort(int* a, int n)
{
	//向下调整建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
		AdjustDown(a, n, i);
	//大堆,向下调整
	int end = n - 1;
	while (end >= 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

建堆的时间复杂度是o(N),排序的时间复杂度是(N*logN)所以堆排序的总时间复杂度是N*logN

二、冒泡排序

2.1 思想

基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

2.2 冒泡排序的实现

方法:从前往后,逐一比较相邻元素,前面的大于或小于后面的则进行交换,每一轮将当前轮最大或最小的元素冒泡到当前论的最后。重复上述过程最后就是有序的。

该排序比较简单,不画图了,不懂得可以看看博主之前写的文章有介绍:

C语言:深入理解指针(2)-CSDN博客

代码实现:

void BubbleSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
		//每一趟拍好一个,最后排完n-1个,最后一个数就没必要比了
	{
		for (int j = 0; j < n - i - 1; j++)//第一趟需要比较的n-1次,第二次需要比较n-2次……
			//所以结束条件跟着i变化
		{
			if (a[j] > a[j + 1])
				Swap(&a[j], &a[j + 1]);
		}
	
	}
}

2.3 冒泡排序的改进

如果比较的过程中,比到中间的时候就有序了,但是我们并不知道,这个时候一直到后面进行的比较都是无效的,所以为了优化这个情况,我们设置一个标志,如果一趟排序中没有发生交换,说明后面都有序了,这个时候就停止冒泡排序!!

void BubbleSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
		//每一趟拍好一个,最后排完n-1个,最后一个数就没必要比了
	{
		int flag = 1;//假设有序
		for (int j = 0; j < n - i - 1; j++)//第一趟需要比较的n-1次,第二次需要比较n-2次……
			//所以结束条件跟着i变化
		{
			if (a[j] > a[j + 1])
			{
				Swap(&a[j], &a[j + 1]);
				flag = 0;//如果没有发生交换,说明不符合有序
			}
		}
		if (flag == 1)
			break;
	}
}

2.4 复杂度分析

时间复杂度:O(N^2)

空间复杂度:O(1)

三、快速排序

3.1 思想

         快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法

其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

       根据区间按照基准值划分的过程,有最早的hoare版本,包括后来深入研究之后的挖坑法、前后指针法、快排法、非递归法……以下博主会用图文的方式和大家一起学习不同方法的实现!!并在这个过程中理解为什么说这中排序方法是二叉树结构。

3.2 hoare快排实现

hoare大佬最初的思想是:

1、在数组中选取一个key值,一般是选择第一个元素或者最后一个元素(我们主要这边主要研究第一个元素做key值)

2、设置两个指针,一个指针right先从往右往左找比key小的值,找到之后,另一个指针left再从左往右走找比key大的值,然后都找到后就交换两边的值,重复上述过程,最后当两个指针相遇的时候,再将相遇点的值与key点的值交换,此时key的左边都是比key小的值,key的右边都是比key大的值,这样就完成了一次选基准值的排序。

3、完成一次找基准值的排序后,使数组有序的问题通过基准值key转化成使key左边和右边都有序的问题,也就是这个key为基准,再分割成两块区间,再分别用上述方法找各自区间的key值,继续重复之前的步骤(递归),直到区间不能被分割,此时的数组就实现了有序。

以上的说法可能大家还不太能理解,我们通过画图来理解hoare大佬的思想。

我们通过上图可以理解为什么说快速排序是一种二叉树结构的排序!!这个过程和二叉树的前序遍历非常相似。既然我们知道了hoare大佬具体想怎么干,我们就明白了这个快排是用递归去实现的,当然现在问题的关键就是我们如果进行基准排序去找到key值对应的位置,下面我们来分析一趟基准排序的过程

       以上就是完成一次基准排序的过程,大家会发现此时恰好key的左边是比key小的,key的右边都是比key大的,其实这并不是巧合,我们后面会分析,这边我们先实现一下一次基准排序的代码!

基准排序代码实现:

int PartSort1(int* a, int left, int right)//hoare基准排序
{
	int keyi = left;
	while (left < right)
	{
	//右先找比key大的
		while (left < right&&a[right] >= a[keyi])
			right--;
	//左找比key小的
		while (left < right && a[left] <= a[keyi])
			left++;
		//找到后,就交换
		Swap(&a[left], &a[right]);
	}
	//此时相遇了,把相遇的位置和keyi的位置交换
	Swap(&a[left], &a[keyi]);
	return left;
}

根据上述的一次基准排序的实现,我们来通过递归实现整体快排的代码:

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;
	int keyi = PartSort1(a, left, right);
	//根据基准值去分割区间,继续进行基准排序
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi+1,right);
}

思考以下问题:

1、怎么判断递归的结束条件呢??

2、hoare大佬是怎么确定每次相遇的时候,相遇点的位置的值一定比key的值小呢??

3、left可以从第二个位置开始走吗?

通过上述的分析,相信大家对hoare大佬的思想已经理解了!!

3.3 挖坑法快排实现

         hoare大佬的思想真的是超凡脱俗,非常厉害,但是也有很多不容易理解的地方,后面就有人进行了改进,发明了挖坑版本的快排,虽然名字叫挖坑,但是比hoare会好理解很多,下面我们来进行挖坑版本的分析!

发明挖坑版本大佬的思想是:

1、先把keyi对应的值记住,然后在这个位置挖坑,right找大,找到了就停下来,将停下来的位置的值去填坑,然后right的位置变成新坑,left找小,找到后就把对应的值填坑,然后left成为新坑,以此类推下去,直到left和right相遇,将之前记住keyi的值填入坑内,这个时候就完成了一次基准排序。

2、除了基准排序的方法和hoare大佬不同,其余地方都是一样的,也是用递归去解决。

 通过这个方法,我们来实现对应的基准排序算法

int PartSort2(int* a, int left, int right)//挖坑基准排序
{
	int key = a[left];//记住key的值
	int hole = left;//开始挖坑
	while (left < right)
	{
		//右先找比key大的
		while (left < right && a[right] >= key)
			right--;
		//找到后,填坑,然后挖新坑
		a[hole] = a[right];
		hole = right;
		//左找比key小的
		while (left < right && a[left] <= key)
			left++;
		//找到后,填坑,然后挖新坑
		a[hole] = a[left];
		hole = left;
	}
	//此时相遇了,把key值放在坑里
	a[hole] = key;
	return hole;
}

整体实现:

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;
	int keyi = PartSort2(a, left, right);
	//根据基准值去分割区间,继续进行基准排序
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi+1,right);
}

我们发现挖坑和填坑的思想特别好理解!!然后接下去就是前后指针版本快排 !!

3.4 前后指针法快排实现

发明前后指针版本大佬的思想是:

1、设置前指针prev,指向首元素,后指针cur指向第二个元素,如果cur开始找小,如果没找到小,就一直往前走,如果找到小的了,就先停下来,然后prev往前走一步,在和cur交换值,然后cur接着走……重复上述步骤,最后cur走出数组返回后,循环终止!此时prev指向的位置和keyi的位置交换。

 

下面我们来实现前后指针快排的基准排序

int PartSort3(int* a, int left, int right) //前后指针基准排序
{
	int prev = left;
	int cur = left + 1;
	int keyi = left;
	while (cur <= right)//cur走出数组循环停止
	{
		//cur一直在走,如果遇到比keyi小的,就停下来等perv走一步后交换,再接着走
		if (a[cur] < a[keyi])
		{
			++prev;
			Swap(&a[prev], &a[cur]);
		}
		cur++;
	}
	//cur出去后,prev的值和keyi交换
	Swap(&a[keyi], &a[prev]);
	return prev;
}

 因为prev和cur指向一个位置的时候,其实没有交换的必要,所以可以将上面代码的优化一下

int PartSort3(int* a, int left, int right) //前后指针基准排序
{
	int prev = left;
	int cur = left + 1;
	int keyi = left;
	while (cur <= right)//cur走出数组循环停止
	{
		//cur一直在走,如果遇到比keyi小的,就停下来等perv走一步后交换,再接着走
		if (a[cur] < a[keyi]&&++prev!=cur)
			Swap(&a[prev], &a[cur]);
		cur++;
	}
	//cur出去后,prev的值和keyi交换
	Swap(&a[keyi], &a[prev]);
	return prev;
}

整体快排的实现:

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;
	int keyi = PartSort3(a, left, right);
	//根据基准值去分割区间,继续进行基准排序
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi+1,right);
}

3.5 快排的复杂度分析

时间复杂度:O(logN*N)

 如果使用了三数取中的优化方法(后面会介绍),那么快排就不可能出现O(N^2)的情况,所以最后时间复杂度是O(logN*N)

空间复杂度:O(logN)

         因为递归是要开销栈帧的,空间可以重复利用而时间不可重复利用。所以这里至多递归到他的深度即h = logN,所以他的空间复杂度是O(logN)

3.6 快排的优化

快排优化的过程源于这道OJ题

力扣:排序数组

看到这题,你可能会很开心:这不就是一个排序吗?我把最厉害的快排用上肯定能过的!!

结果是这样的——

为什么呢??因为力扣的测试用例设置了一个有序的数组来针对快排(复杂度分析过原因了),本质上就是因为有序的时候前面的keyi太小了!!所以我们设置一个改进方法——三数取中,解决有序的情况

3.6.1 三数取中——针对有序

int GetMidIndex(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
			return mid;
		else if (a[right] < a[left])
			return left;
		else
			return right;
	}
	else//a[left] >a[mid]
	{
		if (a[mid] > a[right])
			return mid;
		else if (a[right] > a[left])
			return left;
		else
			return right;
	}
}

封装后,我们前面三种方法的基准值排序都要加上以下代码,这样就可以确保keyi的值是中间值了

int mid = GetMidIndex(a, left, right);
Swap(&a[mid], &a[left]);

你可能觉得这样子应该能过了 ,那我们再测试一下——

结果你发现,又被针对了,有序的情况解决了,又面临着有大量重复数据的排序问题,我们来分析一下:

你会发现,重复其实跟有序的情况是一样的,每次right指针都会走到keyi的位置,这样子时间复杂度也变成O(N^2)了。所以为了解决重复的问题,我们有了三路划分的方法—— 

3.6.2 三路划分——针对重复

因为每次递归需要返回两个边界才行,所以没办法单独封装一个partsort函数 

代码实现: 

void QuickSort2(int* a, int left, int right)
{
	if (left >= right)
		return;
	int mid = GetMidIndex(a, left, right);
	Swap(&a[mid], &a[left]);
	int phead = left;
	int pcur = left + 1;
	int ptail = right;
	int key = a[left];
	while (pcur <= ptail)
	{
		if (a[pcur] < key)
		{
			Swap(&a[pcur], &a[phead]);
			pcur++;
			phead++;
		}
		else if (a[pcur] > key)
		{
			Swap(&a[pcur], &a[ptail]);
			ptail--;
		}
		else
			pcur++;
	}
	QuickSort2(a, left, phead - 1);
	QuickSort2(a, ptail+1,right);
}

结果我们发现,还是过不了,那究竟是哪里出问题了呢?? 

因为里面有一组测试用例针对了三数取中,也就是他把偏大和偏小的数都安排在恰好的位置,所以我们为了针对这种情况,将三数取中的其中一个数改成随机数,接下来我们对三数取中再优化

3.6.3 三数取中再优化

将三数取中的其中一个数的下标变成随机下标:

同时要记得在主函数加上时间种子

int GetMidIndex2(int* a, int left, int right)
{
	int mid = left + (rand() % (right - left));
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
			return mid;
		else if (a[right] < a[left])
			return left;
		else
			return right;
	}
	else//a[left] >a[mid]
	{
		if (a[mid] > a[right])
			return mid;
		else if (a[right] > a[left])
			return left;
		else
			return right;
	}
}
void QuickSort2(int* a, int left, int right)
{
	if (left >= right)
		return;
	int mid = GetMidIndex2(a, left, right);
	Swap(&a[mid], &a[left]);
	int phead = left;
	int pcur = left + 1;
	int ptail = right;
	int key = a[left];
	while (pcur <= ptail)
	{
		if (a[pcur] < key)
		{
			Swap(&a[pcur], &a[phead]);
			pcur++;
			phead++;
		}
		else if (a[pcur] > key)
		{
			Swap(&a[pcur], &a[ptail]);
			ptail--;
		}
		else
			pcur++;
	}
	QuickSort2(a, left, phead - 1);
	QuickSort2(a, ptail+1,right);
}

终于过了!!要重点理解快排的优化思想!! 

3.7 非递归法快排实现

3.7.1 栈实现

我们发现无论是hoare、挖坑还是前后指针,本质区别就是基准排序方法不同,但最后还是用递归去解决的,递归虽好但是有些时候如果数据太大的话还是有可能造成栈空间不够的情况,因此我们应该研究一下如果非递归实现!!——利用栈!

利用栈实现非递归快排的大佬的思想是:

利用栈来存储基准排序需要处理的区间,每次从栈拿出需要处理的区间,再将分割的区间放进栈中,利用栈后进先出的特点,每次都会先处理左边的区间再处理右边的区间,模拟了递归的过程。

我们画个图来理解吧!!(类似二叉树的前序遍历)

 非递归快排代码实现:

需要包含栈的相关代码

void QuickSortNonR1(int* a, int left, int right)
{
	Stack st;
	StackInit(&st);
	//把区间压进去,一定要先压右区间!!
	StackPush(&st, right);
	StackPush(&st, left);
	while (!StackEmpty(&st))
	{
		//将数据弹出来进行进准计算
		int left = StackTop(&st);
		StackPop(&st);
		int right= StackTop(&st);
		StackPop(&st);
		//进行基准计算
		int keyi = PartSort3(a, left, right);
	    //分割区间(left keyi-1)keyi(keyi+1,right)
		//如果对应的区间还能分割,就继续压,要注意要先压后面在压前面
		if (keyi + 1 < right)
		{
			StackPush(&st, right);
			StackPush(&st, keyi+1);
		}
		if (keyi - 1 > left)
		{
			StackPush(&st, keyi-1);
			StackPush(&st,left);
		}
	}
	//会一直到栈为空,此时就拍好序了!!
	StackDestory(&st);
}

3.7.2 队列实现

使用队列也是可以的!!就有点类似二叉树的层序遍历

代码实现:

 需要包含队列的一些文件

void QuickSortNonR2(int* a, int left, int right)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, left);
	QueuePush(&q, right);
	while (!QueueEmpty(&q))
	{
		int left = QueueFront(&q);
		QueuePop(&q);
		int right = QueueFront(&q);
		QueuePop(&q);
		int keyi = PartSort3(a, left, right);
		if (keyi - 1 > left)
		{
			QueuePush(&q, left);
			QueuePush(&q, keyi-1);
		}
		if (keyi + 1 <right)
		{
			QueuePush(&q, keyi +1);
			QueuePush(&q, right);
		}
	}
	QueueDestory(&q);
}

 

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

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

相关文章

备战蓝桥杯---图论之最小生成树

首先&#xff0c;什么是最小生成树&#xff1f; 他就是无向图G中的所有生成树中树枝权值总和最小的。 如何求&#xff1f; 我们不妨采用以下的贪心策略&#xff1a; Prim算法&#xff08;复杂度&#xff1a;&#xff08;nm)logm)&#xff1a; 我们对于把上述的点看成两个集…

MAC VSCODE g++编译器无法编译C++11语法的 解决办法(CodeRunner版本)

如果你是使用的 codeRunner 这个插件&#xff0c;就是这个按钮 coderunner的原理大致是&#xff1a;先判断你这是什么语言&#xff0c;然后有一个 code-runner.executorMap 来对应各个语言是用什么执行语句 我发现&#xff0c;我修改之前&#xff08;无法执行C11语法的原因是&a…

智能汽车专题:智能驾驶2023年度报告

今天分享的是智能汽车系列深度研究报告&#xff1a;《智能汽车专题&#xff1a;智能驾驶2023年度报告》。 &#xff08;报告出品方&#xff1a;量子位智库&#xff09; 报告共计&#xff1a;30页 来源&#xff1a;人工智能学派 顶天立地&#xff1a;技术进阶路线明晰 根据…

echarts制作两个柱状图

let colorList[#02ce8b,#ffbe62,#f17373]; let data1 [90,80,70,50] option { title:[{ // 第一个标题text: 环保检测, // 主标题textStyle: { // 主标题样式color: #333,fontWeight: bold,fontSize: 16},left: 20%, // 定位到适合的位置top: 10%, // 定位到适合的位置},{ //…

小程序获取手机号:快速验证和实时验证

概述 小程序手机号快速验证和实时验证都已经开始收费了。 手机号实时验证组件&#xff0c;在每次请求时&#xff0c;平台均会对用户选择的手机号进行实时验证&#xff1b;每次组件调用成功&#xff0c;收费0.04元手机号快速验证组件&#xff0c;平台会对号码进行验证&#xf…

论文阅读_语音识别_Wisper

英文名称: Robust Speech Recognition via Large-Scale Weak Supervision 中文名称: 通过大规模弱监督实现鲁棒语音识别 链接: https://proceedings.mlr.press/v202/radford23a.html 代码: https://github.com/openai/whisper 作者: Alec Radford, Jong Wook Kim, Tao Xu, Greg…

基于协同过滤的时尚穿搭推荐系统

项目&#xff1a;基于协同过滤的时尚穿搭推荐系统 摘 要 基于协同过滤的时尚穿搭推荐系统是一种能自动从网络上收集信息的工具&#xff0c;可根据用户的需求定向采集特定数据信息的工具&#xff0c;本项目通过研究服饰流行的分析和预测的分析和预测信息可视化时尚穿搭推荐系统…

2024免费人像摄影后期处理工具Portraiture4.1

Portraiture作为一款智能磨皮插件&#xff0c;确实为Photoshop和Lightroom用户带来了极大的便利。通过其先进的人工智能算法&#xff0c;它能够自动识别并处理照片中的人物皮肤、头发和眉毛等部位&#xff0c;实现一键式的磨皮美化效果&#xff0c;极大地简化了后期处理的过程。…

STM32下载后需要复位

下载后需要复位才能自动运行程序&#xff0c;需要以下两步 STEP1 STEP2 一个勾选&#xff0c;一个不勾选。

乡政府|乡政府管理系统|基于Springboot的乡政府管理系统设计与实现(源码+数据库+文档)

乡政府管理系统目录 目录 基于Springboot的乡政府管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、活动信息管理 3、新闻类型管理 4、新闻动态管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推…

内存块与内存池

&#xff08;1&#xff09;在运行过程中&#xff0c;MemoryPool内存池可能会有多个用来满足内存申请请求的内存块&#xff0c;这些内存块是从进程堆中开辟的一个较大的连续内存区域&#xff0c;它由一个MemoryBlock结构体和多个可供分配的内存单元组成&#xff0c;所有内存块组…

JAVA之Java线程核心详解

Java线程核心 1.进程和线程 进程&#xff1a;进程的本质是一个正在执行的程序&#xff0c;程序运行时系统会创建一个进程&#xff0c;并且给每个进程分配独立的内存地址空间保证每个进程地址不会相互干扰。同时&#xff0c;在 CPU 对进程做时间片的切换时&#xff0c;保证进程…

Java 抽象容器类源码剖析

总体介绍 抽象容器类接口和具体容器类的关系如图所示&#xff0c;顶层包括Collection、List、Set、Queue、Deque和Map6个抽象容器类。 AbstractCollection&#xff1a;实现了Collection接口&#xff0c;被抽象类AbstractList、AbstractSet、AbstractQueue继承&#xff0c;Arra…

飞天使-k8s知识点19-kubernetes实操4-资源调度 标签和选择器:Label与Selector的使用-版本回退

文章目录 添加label资源调度 Deployment&#xff1a;创建与配置文件解析rs pod deploy 的关联信息展示Deployment&#xff1a;滚动更新Deployment&#xff1a;回滚回退版本实际操作 添加label [rootkubeadm-master1 test]# kubectl get pod NAME …

OpenCV Mat实例详解 四

OpenCV Mat实例详解三中详细介绍来了OpenCV Mat类的公有静态成员函数&#xff0c;下面介绍OpenCV Mat类的其他常用成员函数。 OpenCV Mat类常用成员函数 Mat & adjustROI (int dtop, int dbottom, int dleft, int dright)&#xff1b; dtop ROI 上边界移动值&#xff0c;如…

Java实现新能源电池回收系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户档案模块2.2 电池品类模块2.3 回收机构模块2.4 电池订单模块2.5 客服咨询模块 三、系统设计3.1 用例设计3.2 业务流程设计3.3 E-R 图设计 四、系统展示五、核心代码5.1 增改电池类型5.2 查询电池品类5.3 查询电池回…

LabVIEW智能监测系统

LabVIEW智能监测系统 设计与实现一个基于LabVIEW的智能监测系统&#xff0c;通过高效的数据采集和处理能力&#xff0c;提高监测精度和响应速度。系统通过集成传感器技术与虚拟仪器软件&#xff0c;实现对环境参数的实时监测与分析&#xff0c;进而优化监控过程&#xff0c;提…

一些配置问题记录

真的很感慨 为什么一开始的下载的软件还能用 卸载或重装后的软件总是存在各种各样的错误 真令人心烦 GNURADIO运行简单的采集信号程序报错&#xff0c; 其实不太理解为什么会出现这类错误&#xff0c;解决方法为 安装 jackd2 软件包&#xff0c;然后尝试手动启动 Jack 服务器…

通过玩游戏学会AWS

游戏名字&#xff1a; Cloud Quest 类型&#xff1a;亚马逊云科技官方出了一款 3D 角色扮演、虚拟城市建造形式的游戏实验课 进入方法&#xff1a;浏览器搜索 Cloud Quest&#xff08;或扫描下方二维码&#xff09;进入 Cloud Quest 课程页。 选择以下的链接 点击进行注册 进…

力扣题目训练(12)

2024年2月5日力扣题目训练 2024年2月5日力扣题目训练476. 数字的补数482. 密钥格式化485. 最大连续 1 的个数148. 排序链表164. 最大间距 2024年2月5日力扣题目训练 2024年2月5日第十二天编程训练&#xff0c;今天主要是进行一些题训练&#xff0c;包括简单题3道、中等题2道和…