洛谷P1923 【深基9.例4】求第k小的数

文章介绍了一种优化的快速排序方法,用于寻找输入列表中第k大的数字,涉及分治策略和时间复杂度优化。作者在实践中遇到超时问题,通过更换输入方式解决。

题目描述

输入n(1 \leq n \leq 5000000且n为奇数)个数字a_i(1\leq a_i \leq 10^9),输出这些数字的第k小的数。最小的数是第0小。

请尽量不要使用nth_element来写本题,因为本题的重点在于练习分治算法。

输入格式

输出格式

输入输出样例

输入

5 1

4 3 2 1 5

输出

2

解题过程

我们首先解读一下题目的要求,即第一行输入两个数n和k,第二行输入n个数,输出n个数中第k大的数。

由于n的数量级不小,我们直接使用long类型存储,同样,a也使用long类型,而关于分治算法,我在此处使用的是快速排序。

然而,直接使用快速排序,仍然无法通过这道题,能够获得分数为60。

以下为普通快速排序的函数:

//排序函数
long Partition(long first, long last)
{
	long i = first, j = last, temp = 0;
	while (i < j)
	{
		//右侧扫描
		while (i < j && arr[i] <= arr[j])
			j--;
		if (i < j) {
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
			i++;
		}
		//左侧扫描
		while (i < j && arr[i] <= arr[j])
			i++;
		if (i < j) {
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
			j--;
		}
	}
	return i;
}

//递归排序
void QuickSort(long first, long last)
{
	if (first >= last)
		return;
	else {
		long pivot = Partition(first, last);
		QuickSort(first, pivot - 1);
		QuickSort(pivot + 1, last);
	}
}

对于这一情况,我们能够做的就是优化代码,由于快速排序是对所选定的轴值的两侧分别排序,我们可以通过判定语句,仅对包含位置为k的一侧进行排序,这样我们可以减少很多的运行时间。

优化后的代码如下:

void QuickSort(long first, long last, long k)
{
	if (first >= last)
		return;
	else 
	{
		long pivot = Partition(first, last);
		if(pivot > k)
			QuickSort(first, pivot - 1, k);
		else if(pivot < k)
			QuickSort(pivot + 1, last, k);
		else
		{
            //输出后直接终止程序,防止重复打印
			cout << arr[pivot];
			exit(0);
		}
	}
}

然而,仅优化快速排序的算法还是没有办法通过这道题,甚至通过的测试点仍然没有变多,依旧超时了。

在那个时候我可以说是百思不得其解,算法已经优化了,怎么还是过不了,看题解后仍旧没有找到解决的方法。所以我直接润去百度,找有没有优化运算时间的方法。

"cin",这个我一直在用的东西,没有想到竟然是它的锅。检索后发现最有可能造成超时的是它后,我就改换了scanf来进行输入。嗯,不超时了,成功AC。

AC代码

#define _CRT_SECURE_NO_WARNINGS //visual studio 2022使用scanf需添加
#include<iostream>
#include<stdio.h>
using namespace std;

long Partition(long first, long last);
void QuickSort(long first, long last , long k);

long arr[5000005] = { 0 };

int main()
{
	//输入n和k
	long n = 0;
	long k = 0;
	scanf("%ld%ld", &n,&k);
	//输入各个数
	for (long i = 0; i < n; i++)
		scanf("%ld",&arr[i]);
	//到k的快速排序
	QuickSort(0, n - 1, k);
	//输出第k大的值
	cout << arr[k];
	return 0;
}

long Partition(long first, long last)
{
	long i = first, j = last, temp = 0;
	while (i < j)
	{
		//右侧扫描
		while (i < j && arr[i] <= arr[j])
			j--;
		if (i < j) {
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
			i++;
		}
		//左侧扫描
		while (i < j && arr[i] <= arr[j])
			i++;
		if (i < j) {
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
			j--;
		}
	}
	return i;
}

void QuickSort(long first, long last, long k)
{
	if (first >= last)
		return;
	else 
	{
		long pivot = Partition(first, last);
		if(pivot > k)
			QuickSort(first, pivot - 1, k);
		else if(pivot < k)
			QuickSort(pivot + 1, last, k);
		else
		{
			cout << arr[pivot];
			exit(0);
		}
	}
}

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值