在非负整数的未排序数组中查找第 k 个最小元素

Find the kth smallest element in an unsorted array of non-negative integers

本文关键字:查找 元素 数组 整数 排序      更新时间:2023-10-16

不允许修改数组(数组是只读的(。 允许使用常量的额外空间。

前任: A : [2 1 4 3 2] k : 3

答案 : 2

我在下面做了。答案是正确的,但需要提高内存效率。

void insert_sorted(vector<int> &B, int a,int k)
{
for(int i=0;i<k;i++)
{
if(B[i]>=a)
{
for(int j=k-1;j>i;j--)
B[j]=B[j-1];
B[i]=a;
return;
}
}
}
int Solution::kthsmallest(const vector<int> &A, int k) {
vector <int> B;
for(int i=0;i<k;i++)
{
B.push_back(INT_MAX);
}
int l=A.size();
for(int i=0;i<l;i++)
{
if(B[k-1]>=A[i])
insert_sorted(B,A[i],k);
}
return B[k-1];
}

一种可能的解决方案是二叉搜索。

A作为输入数组;我们希望找到一个数字b使得A中的k项小于b

显然,b必须在[0, max(A)]范围内。 我们从这个范围开始进行二叉搜索。

假设我们正在范围内搜索[lo, hi]. 让我们c = (lo + hi)/2哪个是中间的枢轴。 有三种情况:

  • A少于c的项目数小于k。 在这种情况下,我们搜索的数字应该大于c,所以它应该在范围内(c, hi]

  • A中小于c的项目数大于k。 同样,我们搜索的数字也在范围内[lo, c)

  • 小于cA中的项目数等于k。 在这种情况下,答案是A中大于或等于c的最小元素。这可以通过再次在A中进行线性搜索来找到

复杂度O(n log m),其中mA中的最大元素。

/* assume k is 0 based, i.e. 0 <= k < n */
int kth_element(const vector<int> &A, int k){
int lo = 0, hi = *max_element(A.begin(), A.end());
while (lo <= hi){
int mid = (lo + hi) / 2;
int rank_lo = count_if(A.begin(), A.end(), [=](int i){ return i < mid;}); 
int rank_hi = count_if(A.begin(), A.end(), [=](int i){ return i <= mid;});
if (rank_lo <= k && k < rank_hi)
return mid;
if (k >= rank_hi)
lo = mid + 1;
else
hi = mid - 1;
}
}

虽然它不是这个特定问题的答案(因为它需要一个可修改的集合(,但有一个名为std::nth_element的函数,它重新排列元素,使第k个元素位于位置k,并且位置小于k的所有元素都小于或等于第k个元素, 其中k是输入参数。

这个问题不要求任何时间限制。O(nk)解决方案相当简单,通过迭代数组k次(最多(,每次丢弃一个元素(及其重复项(。

int FindKthSmallesr(const std::vector<int>& v, int k) {
// assuming INT_MIN cannot be a value. Could be relaxed by an extra iteration.
int last_min = INT_MIN;
while (k > 0) {
int current_min = INT_MAX;
for (int x : v) {
if (x <= last_min) continue;
current_min = std::min(current_min, x);
}
last_min = current_min;
for (int x : v) {
if (x == current_min) k--;
}
}
return last_min;
}

代码在 ideone: http://ideone.com/RjRIkM

如果只允许常量的额外空间,我们可以使用简单的 O(n*k( 算法。

int kth_smallest(const vector<int>& v, int k) {
int curmin = -1;
int order = -1;
while (order < k) { // while kth element wasn't reached
curmin = *min_element(v.begin(), v.end(), [curmin](int a, int b) {
if (a <= curmin) return false; 
if (b <= curmin) return true;
return a < b;
}); // find minimal number among not counted yet
order += count(v.begin(), v.end(), curmin); // count all 'minimal' numbers
}
return curmin;
}

在线版玩法:http://ideone.com/KNMYxA