Description
求数组的第k小,数字数量非常多。
Input
每组数据给出
n m k
表示有n
个数,求第k
小,数组的数字由以下规则得到:ai = mi mod (109+7), i = 1, 2, ..., n
其中 1 ≤ n, m ≤ 5 × 107, 1 ≤ k ≤ n,数据保证得到的数组元素大部分互不相等。
Output
输出第k小的数
Sample Input
3 2 2Sample Output
4
我们可以采用快速排序算法的一种变式来实现
首先先回顾一下快速排序算法,先贴一个快排的代码
void QuickSort(int arr[], int begin, int end)
{
//只有一个数或者区间不存在时
if (begin >= end) return;
int left = begin;
int right = end;
//选取左边第一个为key
int key = begin;
while (begin<end)
{
//右边选小
while (arr[end] >= arr[key] && begin < end)
{
end--;
}
//左边选大
while (arr[begin] <= arr[key] && begin < end)
{
begin++;
}
swap(arr[begin], arr[end]);
}
//此时left和right指针已经相遇
swap(arr[key], arr[end]);
//递归左右区间
key = end;
QuickSort(arr, left, key - 1);
QuickSort(arr, key + 1, right);
}
我们观察一下,第一趟快速排序结束后数组是什么样子的
当第一趟排序完成之后,我们将key放在了数组中的某一个位置,在这个位置,key左边的数都比它小,key右边的数都比它大。所以key的下标就对应了它在数组中是第k小的数。
所以我们并不需要完成整个快速排序的过程,因为只关心每次key在数组中的下标,至于a[left,key-1]和a[key+1,right]之间的数据有序与否,我们并不关心。
如图所示 [3 1 2 5 4 6 9 7 10 8],key(6)在数组中是第六个数,这代表着它是第六小的数,至于左半部分[3 1 2 5]它们之间不是有序,并不影响,我们知道它们比key小就行了
因此我们改变一下代码即可
if (target_pos + 1 == k) return arr[target_pos];
else if (target_pos + 1 > k) return QuickSort(arr, left, target_pos - 1, k);
else return QuickSort(arr, target_pos + 1, right, k);
完整代码:
#include<iostream>
using namespace std;
int a[50000000];
int QuickSort(int arr[], int begin, int end, int k)
{
int left = begin;
int right = end;
//选取左边第一个为key
int key = begin;
while (begin < end)
{
//右边选小
while (arr[end] >= arr[key] && begin < end)
{
end--;
}
//左边选大
while (arr[begin] <= arr[key] && begin < end)
{
begin++;
}
swap(arr[begin], arr[end]);
}
//此时left和right指针已经相遇
swap(arr[key], arr[end]);
key = end;
int target_pos = end;
//数组下标从0开始,所以需要+1
if (target_pos + 1 == k) return arr[target_pos];//找到第k小的数了,直接返回
//递归左半区间
else if (target_pos + 1 > k) return QuickSort(arr, left, target_pos - 1, k);
//递归右半区间
else return QuickSort(arr, target_pos + 1, right, k);
}