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

时间:2017-07-05 05:55:35

标签: c++ algorithm

不允许修改数组(该数组是只读的)。 允许使用恒定的额外空间。

例如: 答:[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];
}

3 个答案:

答案 0 :(得分:3)

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

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

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

假设我们在范围[lo, hi]内搜索。 让c = (lo + hi)/2作为中间支点。 有三种情况:

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

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

  • 范围内
  • A小于c的项目数等于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 th元素位于k位置,位置小于k的所有元素小于或等于 k 元素,其中k是输入参数。

答案 1 :(得分:1)

问题不是要求任何时间限制。 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

答案 2 :(得分:1)

如果只允许恒定的额外空间,我们可以使用简单的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