不允许修改数组(该数组是只读的)。 允许使用恒定的额外空间。
例如: 答:[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];
}
答案 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)
,其中m
是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;
}
}
虽然它不是这个特定问题的答案(因为它需要一个可修改的集合),但有一个名为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;
}