ALGO-1区间K大数查询

题目
问题描述
给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个。
输入格式
第一行包含一个数n,表示序列长度。
第二行包含n个正整数,表示给定的序列。
第三个包含一个正整数m,表示询问个数。
接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个。序列元素从1开始标号。
输出格式
总共输出m行,每行一个数,表示询问的答案。
样例输入
5
1 2 3 4 5
2
1 5 2
2 3 2
样例输出
4
2
数据规模与约定
对于30%的数据,n,m<=100;
对于100%的数据,n,m<=1000;
保证k<=(r-l+1),序列中的数<=106。
题解
快排的原理:利用快速排序将无序序列转换为有序序列的过程中,经过多次的划分;(这里假定进行降序排列)在每一次的划分中,在序列中找到一个枢轴(pivot),划分的结果是 pivot 左边的数均比它大,右边的数均比它小;然后对子序列进行同样的操作,递归进行、直到所有子序列有序为止。
改造:我们的目标是找到第K大的数,若在一次划分之后、pivot左边的数(加上它本身)共有K个,那么pivot位置上的数就是我们要找的第K大的数;其一:我们不必要求前K-1大的数有序,所以不必继续进行递归划分;其二:每一次的划分都将原序列分为左、右两个子序列,快排算法需要对这两个子序列都继续进行递归的划分,而在这里我们只需要根据情况(具体看算法步骤)选择一个子序列继续划分即可;因此这种求第K大的数算法的时间复杂度小于快速排序的复杂度,为O(n*logK)
算法步骤:经过一次划分(partition)之后,枢轴pivot将原序列划分为两个部分:S和T [即原序列变为(S T)、pivot包含在子序列S中、注意使用降序排序],会出现下列三种情况:
1.子序列S中有K个数,此时pivot位置即为第K大的数,算法结束
2.子序列S中的数字个数小于K,假设个数为L,则需要子序列T中继续递归划分出来前(K-L)个数
3.子序列S中的数字个数大于K,则需要子序列S中继续递归划分出来前K个数
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std; 
/*快速排序的一次划分*/
int partition(int a[], int low, int high) {
	int i = low, j = high, x = a[low];
	while(i<j) {
		while(i<j && a[j]<=x) { j--; }
		a[i] = a[j];
 
		while(i<j && a[i]>=x) { i++; }
		a[j] = a[i];
	}
	a[i] = x;
	return i;
} 
/* 降序排序,当一次划分之后、pivot左边的数(包括它本身)恰为k个时,停止划分*/
void find_kmax(int a[], int low, int high, int k) {
   	if (low < high) {
    	        int poi = partition(a, low, high);// 得到一次划分之后 pivot的位置
                int len = poi - low + 1;// 计算子序列S的长度
		if (len < k) {// 情况2
			find_kmax(a, poi + 1, high, k - len);
		} else if (len > k) {// 情况3
			find_kmax(a, low, poi - 1, k);
		}
     }
}
int main() {
	int arr[] = {23, 50, 500, 4, 100, 300, 200, 99, 400};
	int len = sizeof(arr) / sizeof(int);// 求数组长度
 
	int l, r, k;// 区间为[l, r],从1开始
        scanf("%d %d %d", &l, &r, &k);
 
        int a[100];
        memcpy(a, arr, sizeof(arr));// 将arr数组的元素copy到a数组中,这么做是为了避免破坏原数组、能够进行多次不同区间的查询
        find_kmax(a, l-1, r-1, k);// 注意区间下标与数组下标的转换
        printf("%d\n", a[l-1 + k-1]);// 注意第k大的数在数组a中的位置!
 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42403069/article/details/86079151