您的位置:首页 > 其它

算法训练 区间k大数查询

2017-02-28 11:57 507 查看
算法训练 区间k大数查询  

时间限制:1.0s   内存限制:256.0MB

   

问题描述

给定一个序列,每次询问序列中第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。

裸的 区间K大数查询问题,下面是两种常用的方法:

方法一:利用快速排序的原理

#include <iostream>
#include <cstdio>
#include <cstring>
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;
}

void find_kmax(int a[], int low, int high, int k) {
if (low < high) {
int poi = partition(a, low, high);
int len = poi - low + 1;
if (len < k) {
find_kmax(a, poi + 1, high, k - len);
} else if (len > k) {
find_kmax(a, low, poi - 1, k);
}
}
}

int main() {
int n, arr[1005];
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

int m, l, r, k, a[1005];
scanf("%d", &m);
while (m--) {
scanf("%d %d %d", &l, &r, &k);
memcpy(a, arr, sizeof(arr));
find_kmax(a, l-1, r-1, k);
printf("%d\n", a[l - 1 + k - 1]);
}
return 0;
}

方法二:利用堆排序的原理

// 没有方法一效率高

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

// 循环筛选的子过程
void adjust_loop(int *heap, int i, int len) {
if (i < len) {
int l = 2 * i + 1, r = 2 * i + 2;
if (r < len && heap[r] < heap[i]) {
int tmp = heap[i];
heap[i] = heap[r];
heap[r] = tmp;

adjust_loop(heap, r, len);
}
if (l < len && heap[l] < heap[i]) {
int tmp = heap[i];
heap[i] = heap[l];
heap[l] = tmp;

adjust_loop(heap, l, len);
}
}
}

// 建立小顶堆,从最大下标的/2(下取整)的位置开始,逆向筛选
void heap_adjust(int *heap, int len) {
for (int i = (len-1)/2; i >= 0; i--) {
adjust_loop(heap, i, len);
}
}

void find_kmax(int arr[], int l, int r, int k, int *heap) {
// 原数组区间[l, r]中的前k个元素先建一个小顶堆
for (int i = l; i < k+l; i++) {
heap[i-l] = arr[i];
}
heap_adjust(heap, k);

// 剩余的(r-l+1)-k个元素进行更新
for (int j = k+l; j <= r; j++) {
// 比最小的大,可以插入堆中
if (arr[j] > heap[0]) {
heap[0] = arr[j];
heap_adjust(heap, k);
}
}
}

int main() {
int n, arr[1005];
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

int m, l, r, k;
scanf("%d", &m);
while (m--) {
scanf("%d %d %d", &l, &r, &k);

int *heap = new int[k];
find_kmax(arr, l-1, r-1, k, heap);
printf("%d\n", heap[0]);
delete heap;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法