分治算法求N个数中第K小(大)的数

这个学期开算法课,跟着进度写写代码就好。这周讲分治,说到了求N个数中第K小(大)数的问题,写写看。

分治算法的复杂度是O(n),用到了快速排序的思路:先选取一个参考数进行一次快排,拿升序来说的话,快排之后左边所有数<参考数,右边所有数>参考数,然后根据左右部分各自包含元素的个数,计算要求的元素在哪个区间内(要求的元素或是左区间中的第k小数,或是右区间中第[k-j]小数,j为左区间的长度),然后递归求解。

本来pku 2104和pku 2761都是求第K小数的题,无奈用这个算法TLE,只能用后面的划分树或是其他复杂度更低的算法来做,以后再说吧。我这里只贴用这个算法做的,虽然交上去会TLE...

#include 
 
using namespace std;
 
int partition(int[], int, int);
int Select(int[], int, int, int); 
 
int main()
{
	int n, m;
	int l, r, k;
	int v[100002];
	int d[100002];
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> v[i];
	while (m--)
	{
		cin >> l >> r >> k;
		for (int j = l; j <= r; j++) d[j] = v[j];
		cout << Select(d, l, r, k) << endl;
	}
 	return 0;
}
 
//一次快速排序 
int partition(int s[], int l, int r)
{
	if (l < r)
	{
		int i = l;
		int j = r;
		int x = s[i];
		while (i < j)
		{
			while (i < j && s[j] >= x) j--;
			if (i < j) s[i++] = s[j];
			while (i < j && s[i] < x) i++;
			if (i < j) s[j--] = s[i];
		}
		s[i] = x;
		return i;
	}
	return -1;
}
 
//分治找K-th Number 
int Select(int s[], int l, int r, int k)
{
	if (l > r) return -1;
	if (l == r) return s[l];
	//得到中间数的下标 
	int i = partition(s, l, r);
	//j为左区间长度 
	int j = i - l + 1;
	//位置大就在左区间找,否则就在右区间找
	if (j == k) return s[i];
	else if (j > k) return Select(s, l, i, k);
	else return Select(s, i+1, r, k-j);
}

     

你可能感兴趣的:(算法设计,C++)