簡體   English   中英

在未排序的非負整數數組中找到第k個最小的元素

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

不允許修改數組(數組是只讀的)。 允許使用恆定的額外空間。

例如: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)范圍內

  • 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個元素位於位置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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM