[英]How to find the kth largest element in the union of two sorted arrays?
我需要在两个排序的数组中找到k
最大的元素,但是有一个扭曲。
当k>max(m,n)
时k<=max(m,n)
该算法假设k<=max(m,n)
并且索引出错。 在我的问题中,我知道将永远是k>(m+n)/2
,因此k>min(m,n)
所以我需要改变JulesOlléon的答案......我只是看不出哪一点:〜
我已经找到了这个链接第3页,但是那里有bug(当实现时,它没有返回正确的答案)
我知道快速解决方法是将两个数组乘以-1并取该联合中的k个最小值并将该答案乘以-1但这将使代码不可读。
这不是作业。
好吧,我想我很想念尼尔的回答或其他什么,因为这就是我给'他'的东西
#include <algorithm>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <vector>
#include <Eigen/Dense>
using namespace Eigen;
using Eigen::VectorXf;
using Eigen::VectorXi;
float getNth(VectorXf& v1,VectorXf& v2,int& n){
int step=(n/4),i1=(n/2),i2=(n-i1);
while(!(v2(i2)>=v1(i1-1) && v1(i1)>v2(i2-1))){
if(v1(i1-1)>=v2(i2-1)){
i1-=step;
i2+=step;
} else {
i1+=step;
i2-=step;
}
step/=2;
if(!step) step=1;
}
if(v1(i1-1)>=v2(i2-1))
return v1(i1-1);
else
return v2(i2-1);
}
int main(){
int p,q,n,k,l;
float sol;
std:: cout << "enter p " << std::endl;
std::cin >> p;
std:: cout << "enter q " << std::endl;
std::cin >> q;
n=p+q;
std:: cout << " enter k larger than " << std::min(p,q) << " and smaller than " << n-1 << std::endl;
std::cin >> k;
k=n-k-1;
srand(time(NULL));
VectorXf v1=VectorXf::Random(p);
srand(time(NULL));
VectorXf v2=VectorXf::Random(q);
VectorXf v3(n);
v3 << v1, v2;
std::sort(v3.data(),v3.data()+v3.size(),std::greater<float>()); //std::greater<float>()
std::sort(v1.data(),v1.data()+v1.size(),std::greater<float>());
std::sort(v2.data(),v2.data()+v2.size(),std::greater<float>());
sol=getNth(v1,v2,k);
std::cout << sol << std::endl;
std::cout << v3(k) << std::endl;
return 0;
}
这就是我得到的:
enter p
12
enter q
32
enter k larger than 12 and smaller than 43
13
nthoftwo: /Desktop/work/p1/geqw4/vi3/out/sp/ccode/eigen/Eigen/src/Core/DenseCoeffsBase.h:409: Eigen::DenseCoeffsBase<Derived, 1>::Scalar& Eigen::DenseCoeffsBase<Derived, 1>::operator()(Eigen::DenseCoeffsBase<Derived, 1>::Index) [with Derived = Eigen::Matrix<float, -0x00000000000000001, 1>, Eigen::DenseCoeffsBase<Derived, 1>::Scalar = float, Eigen::DenseCoeffsBase<Derived, 1>::Index = long int]: Assertion `index >= 0 && index < size()' failed.
Aborted (core dumped)
如果您不熟悉eigen:错误是由getNth(v1,v2,k)
引起的索引超出范围的错误
这是对JF Sebastian下面简单而优雅的解决方案的一个非常小的修改 - 所有错误都是我的,但似乎有效。 目的是使用原始索引(即我不确定Neil的想法是不可或缺的)。
#include <algorithm>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <vector>
#include <cassert>
#include <iterator>
#include <Eigen/Dense>
using namespace Eigen;
using Eigen::VectorXf;
using Eigen::VectorXi;
template<class RandomIterator,class Compare>
typename std::iterator_traits<RandomIterator>::value_type
nsmallest(RandomIterator firsta,RandomIterator lasta,RandomIterator firstb,RandomIterator lastb,size_t n,Compare less) {
assert(n<static_cast<size_t>((lasta-firsta)+(lastb-firstb)));
if (firsta==lasta) return *(firstb+n);
if (firstb==lastb) return *(firsta+n);
size_t mida=(lasta-firsta)/2;
size_t midb=(lastb-firstb)/2;
if ((mida+midb)<n)
return less(*(firstb+midb),*(firsta+mida))?
nsmallest(firsta,lasta,firstb+midb+1,lastb,n-(midb+1),less):
nsmallest(firsta+mida+1,lasta,firstb,lastb,n-(mida+1),less);
else
return less(*(firstb+midb),*(firsta+mida))?
nsmallest(firsta,firsta+mida,firstb,lastb,n,less):
nsmallest(firsta,lasta,firstb,firstb+midb,n,less);
}
int main(){
int p,q,n,k,l;
float sol;
std:: cout << "enter p " << std::endl;
std::cin >> p;
std:: cout << "enter q " << std::endl;
std::cin >> q;
n=p+q;
std:: cout << " enter k larger than " << std::min(p,q) << " and smaller than " << n-1 << std::endl;
std::cin >> k;
srand(time(NULL));
VectorXf v1=VectorXf::Random(p);
srand(time(NULL));
VectorXf v2=VectorXf::Random(q);
VectorXf v3(n);
v3 << v1, v2;
std::sort(v3.data(),v3.data()+v3.size());
std::sort(v1.data(),v1.data()+v1.size());
std::sort(v2.data(),v2.data()+v2.size());
sol=nsmallest(v1.data(),v1.data()+v1.size(),v2.data(),v2.data()+v2.size(),k,std::less<float>());
//if it works, these two should return the same.
std::cout << sol << std::endl;
std::cout << v3(k) << std::endl;
return 0;
}
从你的评论我明白你想找到给定2个反向排序的数组的第k个最小值,例如,对于a={5,4,3}, b={2,1,0};
并且k=1
,预期结果为0
即最小值 - 第一个最小值(表示k
从1
计数)。
鉴于nsmallest()
函数适用于已排序的数组并接受自定义比较器,您可以:
#include <functional> // greater<>
#include <iostream>
#define SIZE(a) (sizeof(a) / sizeof(*a))
int main() {
int a[] = {5,4,3};
int b[] = {2,1,0};
int k = 1; // find minimum value, the 1st smallest value in a,b
int i = k - 1; // convert to zero-based indexing
int v = nsmallest(a, a + SIZE(a), b, b + SIZE(b),
SIZE(a)+SIZE(b)-1-i, std::greater<int>());
std::cout << v << std::endl; // -> 0
return v;
}
我用@ Neil的建议来修复索引和@ lambdapilgrim的算法答案 :
#include <cassert>
#include <iterator>
template<class RandomIterator, class Compare>
typename std::iterator_traits<RandomIterator>::value_type
nsmallest(RandomIterator firsta, RandomIterator lasta,
RandomIterator firstb, RandomIterator lastb,
size_t n,
Compare less) {
assert(n < static_cast<size_t>((lasta - firsta) + (lastb - firstb)));
if (firsta == lasta) return *(firstb + n);
if (firstb == lastb) return *(firsta + n);
size_t mida = (lasta - firsta) / 2;
size_t midb = (lastb - firstb) / 2;
if ((mida + midb) < n)
return less(*(firstb + midb), *(firsta + mida)) ?
nsmallest(firsta, lasta, firstb + midb + 1, lastb, n - (midb + 1), less) :
nsmallest(firsta + mida + 1, lasta, firstb, lastb, n - (mida + 1), less);
else
return less(*(firstb + midb), *(firsta + mida)) ?
nsmallest(firsta, firsta + mida, firstb, lastb, n, less) :
nsmallest(firsta, lasta, firstb, firstb + midb, n, less);
}
第k
个最大元素也是m + n + 1 - k
th *最小元素,因此您可以尝试以这种方式解决问题。
*从1开始计数。如果k
从0开始计数,则使用m + n - 1 - k
代替。
我相信你想要类似于mergesort的合并步骤的东西,你可以逐步地将m的第i个元素与n的第j个元素进行比较 - 但是不是将数值存储在数组中,而是仅仅寻找第k个最小的 - 所以当你找到它时,返回该值(和/或其索引)并退出该函数。
我不确定这笔交易是关于k> max(m,n)的!
简单的解决方案:
def find(v1, start1, end1, v2, start2, end2, k):
i = (start1+end1)/2
j = binsearchrank(v2, start2, end2, v1[i])
ranki = (i-start1+1) + (j-start2)
if ranki > k:
return find(v2, start2, j, v1, start1, i, k)
elif ranki < k:
return find(v2, j, end2, v1, i+1, end1, k-ranki)
else:
return v1[i]
复杂度为O(log ^ 2n)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.