找到数组中任意小数据及间隔最小 数据

该博客探讨了如何在给定数组中高效地找到第k小的数字以及间隔最小的值。建议使用堆排序或选择排序,但推荐采用分治策略,结合快速排序的划分过程来缩小搜索范围。当存在重复数字时,需要避免划分错误导致死循环。对于寻找间隔最小值的问题,同样运用分治策略,将数组分为两部分并分别查找,最后从三者中选取最小间隔。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                             找到一组数字中,第k小的数字

这个题目是:给定一个数组,找到数组中任意第k小的数字。看完这个题目,我想到的就是我把这个数组,进行排序。这时候我们想要第几小就可以得到第几小了哈,是不是很方便。

在选择的排序算法的时候我们尽量选择堆排序和选择排序,为什么呢?因为这两个排序算法,我们不需要将整个数组排序完,我们只需要将需要查找的排序出来就可以了。

但是这种方法肯定是费时的,我们可以用分治的思想去做,结合快排的一次划分来缩小规模。

 对于快排的一次划分,我们可以将基准的这个数字放进数组中,他所在的位置,也就是说前面的数据都是他小,后面的数据都比他大。换句话说它的下标就是他在数组中的第几小,这样我们就可以扔掉一部分规模,依次来找到元素中的第几小。

这里我们列举了一部分,我们只需要将得到的值,如果大于需要的就在左边找,小于就在右边找。

template<class Type>
int Partition(Type *ar, int left, int right)
{
	int i = left, j = right;
	Type tmp = ar[i]; 
	while (i < j)
	{
		while (i<j && ar[j] > tmp) --j;
		if (i<j) ar[i] = ar[j];
		while (i<j && ar[i] <= tmp) ++i;
		if (i<j) ar[j] = ar[i];
	}
	ar[i] = tmp;
	return i;
}

template<class Type>
const Type & Select_K(Type *ar,int left,int right,int k)
{
	if(left == right && k == 1) return ar[left];
	int index = Partition(ar, left, right);
	int pos = index - left + 1;
	if(k <= pos) return Select_K(ar,left,index,k);
	else return Select_K(ar,index+1,right,k-pos);
}
template<class Type>
const Type & Select_K_Min(Type *ar,int n, int k)
{
	assert(ar != NULL && n > 0 && k>=1 && k <= n);

	return Select_K(ar,0,n-1,k);
}

但是有一个问题就是,我们在这里面不能有重复的数字,如果有重复数字,划分就会有问题,造成死循环。

 

在这里我们就又遇到了这样的一个题,在一个数组中,我们找到差值最小的值;

如在数组:56,23,12,84,92,28,38,32,100,45,67,78,14;这个值就是2。

这里我们也用到了分治的思想,吧一个数组分成两个部分,左边找间隔最小的,右边找间隔最小的,还有分隔的这部分,然后三个里面最小的。

这样我们就可以吧数组缩小,然后到最后剩下两个值的时候,可以算出来。

template<class Type>
int Partition(Type *ar, int left, int right)
{
	int i = left, j = right;
	Type tmp = ar[i]; //
	while (i < j)
	{
		while (i<j && ar[j] > tmp) --j;
		if (i<j) ar[i] = ar[j];
		while (i<j && ar[i] <= tmp) ++i;
		if (i<j) ar[j] = ar[i];
	}
	ar[i] = tmp;
	return i;
}

template<class Type>
const Type & Select_K(Type *ar,int left,int right,int k)
{
	if(left == right && k == 1) return ar[left];
	int index = Partition(ar, left, right);
	int pos = index - left + 1;
	if(k <= pos) return Select_K(ar,left,index,k);
	else return Select_K(ar,index+1,right,k-pos);
}
template<class Type>
const Type & Select_K_Min(Type *ar,int n, int k)
{
	assert(ar != NULL && n > 0 && k>=1 && k <= n);

	return Select_K(ar,0,n-1,k);
}
int MaxS1(int *br,int left,int right)
{
	return br[right];
}
int MinS2(int *br,int left,int right)
{
	int min = br[left];
	for(int i =left + 1; i<=right; ++i)
	{
		if(min > br[i])
		{
			min = br[i];
		}
	}
	return min;
}
int Min3d(int a,int b,int c)
{
	return a < (b < c ? b : c) ? a : (b < c ? b : c);
}
int Cpair_min(int *br,int left,int right)
{
	if(right - left <= 0) return INT_MAX;
	int k = (right - left + 1)/2;
	int index = k + left - 1;  
	Select_K(br,left,right,k);
	int mind1 = Cpair_min(br,left,index);    
	int mind2 = Cpair_min(br,index+1,right); 
	int smax = MaxS1(br,left,index); 
	int smin = MinS2(br,index+1,right); 

	return Min3d(mind1,mind2,smin-smax);
}
int Cpair_ar(int *br,int n) 
{
	if(NULL == br || n < 2) return INT_MAX;
	return Cpair_min(br,0,n-1);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值