算法训练 区间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;
}
时间限制: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;
}
相关文章推荐
- 蓝桥杯 算法训练 区间k大数查询(水题)
- 算法训练 区间k大数查询
- 算法训练 区间k大数查询
- 算法训练 区间k大数查询
- 蓝桥 算法训练 区间k大数查询(sort函数)
- 蓝桥杯_算法训练_区间k大数查询
- 算法训练 区间k大数查询
- 算法训练 区间k大数查询
- 算法训练 1 区间k大数查询
- 蓝桥杯--算法训练 区间k大数查询
- 蓝桥杯 算法训练 区间K大数查询 冒泡法排序重温
- 算法训练 区间k大数查询
- 算法训练 区间k大数查询 排序 查找
- 【算法训练】区间k大数查询
- 算法训练 区间k大数查询
- 算法训练 区间k大数查询(数组复制、排序算法、递归查找)
- 算法训练 区间k大数查询 Java 解题
- 算法训练 区间k大数查询
- 蓝桥杯算法训练 区间k大数查询
- 2016蓝桥杯算法训练——区间k大数查询