Reputation: 21
Not allowed to modify the array ( The array is read only ). Using constant extra space is allowed.
ex: A : [2 1 4 3 2] k : 3
answer : 2
I did it below way. The answer is correct but need to be more memory efficient.
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];
}
Upvotes: 1
Views: 2378
Reputation: 414
One possible solution is binary search.
Let A
be the input array; we want to find a number b
such that exactly k
items in A
are smaller than b
.
Obviously, b
must be inside the range [0, max(A)]
.
And we do binary search starting with this range.
Suppose we are searching within range [lo, hi]
.
Let c = (lo + hi)/2
which is the middle pivot.
There are three cases:
number of items in A
less than c
are less than k
.
In this case the number we search for should be larger than c
, so it should be in range (c, hi]
number of items in A
less than c
are larger than k
.
Similarly, the number we search for is in range [lo, c)
number of items in A
less than c
equals to k
.
In this case, the answer is the minimum element in A
that is greater than or equals to c
. This can be find by doing a linear search in A
again
The complexity is O(n log m)
, where m
is the max element in A
.
/* 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;
}
}
Although it's not the answer to this particular problem (as it requires a modifiable collection), there is a function called std::nth_element
, which rearranges the elements so that the kth element is at position k
, and all elements at positions less than k
are smaller than or equal to the kth element, where k
is a input parameter.
Upvotes: 3
Reputation: 9117
If only constant extra space is allowed, we can use a simple O(n*k) algorithm.
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;
}
online version to play with: http://ideone.com/KNMYxA
Upvotes: 1
Reputation: 178431
The question does not ask for any time constraints. An O(nk)
solution is fairly simple, by iterating the array k
times (at most), and discarding one element (and its duplicates) each time.
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;
}
Code on ideone: http://ideone.com/RjRIkM
Upvotes: 1