我正在寻找具有最小时间和空间复杂度的以下算法的解决方案。
给定两个数组a和b,找到所有元素对(a1,b1),使得a1属于数组A,b1属于数组B,其总和a1 + b1 = k(任何整数)。
我能够提出O(n log n)方法,我们将其中一个数组排序为A,对于数组B中的每个元素b,对排序数组A进行二进制搜索以获得值(Kb)
我们可以进一步改进吗?
答案 0 :(得分:18)
如果对数组进行了排序,则可以在线性时间和常量存储中进行排序。
如果数组最初是未排序的,那么您可以先对它们进行排序,然后使用上面的算法。根据您期望的数据类型,可以使用几种不同的方法对它们进行排序:
比较排序平均需要O(n log n)时间。最后两个比O(n log(n))快,但如果输入数组中可能值的范围非常大,则可能不切实际。
答案 1 :(得分:10)
如果您对最大可能数量有限制(让我们将其命名为M),那么您可以在O(M + n)中找到解决方案。
false的布尔数组和标记为真的A元素的所有值。然后,对于B的每个元素b,检查元素编号K-b是否标记为真。
如果您使用的是哈希映射而不是大数组,则可以改进它。但我不会认为在这种问题中,哈希映射是一种欺骗行为。
无论如何,它会给你O(n)插入,然后O(n)用于查询,O(n)总计。
编辑:
这可能有用的一种情况。
使用我的想法不是布尔而是整数(每次运行时增加)会给你一个复杂的:
你正在使用更多的空间,但在这种情况下你的速度提高了一个因子log(n)〜= 20!
答案 2 :(得分:3)
我会创建一个包含一个数组元素的哈希表,然后迭代另一个查找k - a(n)
的数组,如果查找成功则生成一个输出元素。这将使用O(n)空格和时间。
在C#中,它可能如下所示:
var bSet = new HashSet(B);
var results = from a in A
let b = k - a
where bSet.Contains(b)
select new { a, b };
答案 3 :(得分:1)
template< typename T >
std::vector< std::pair< T, T > >
find_pairs(
std::vector< T > const & a, std::vector< T > const & b, T const & k ) {
std::vector< std::pair< T, T > > matches;
std::sort( a.begin(), a.end() ); // O( A * lg A )
std::sort( b.begin(), b.end() ); // O( B * lg B )
typename std::vector< T >::const_iterator acit = a.begin();
typename std::vector< T >::const_reverse_iterator bcit = b.rbegin();
for( ; acit != a.end(); /* inside */ ) {
for( ; bcit != b.rend(); /* inside */ ) {
const T sum = *acit + *bcit;
if( sum == k ) {
matches.push_back( std::pair< T, T >( *acit, *bcit ) );
++acit;
++bcit;
}
else if( sum < k ) {
++acit;
}
else { // sum > k
++bcit;
}
}
} // O( A + B )
return matches;
}
答案 4 :(得分:0)
我使用了C ++,它似乎给了我想要的结果。希望这是你想要的。
using namespace std;
using data=std::pair<int,int>;
void search_pairs(std::vector<int>& A, std::vector<int>& B, const int total, std::vector<data>& output){
std::sort(A.begin(),A.end(),[](const int i,const int j)->bool{return (i<j);});
std::sort(B.begin(),B.end(),[](const int a,const int b)->bool{return (a<b);});
std::vector<int>* minV(nullptr);
std::vector<int>* maxV(nullptr);
if(A.size()>B.size()) {minV=&B;maxV=&A;}
else {minV=&A;maxV=&B;}
for(auto&& itr:(*minV) ){
auto remain(total-itr);
if (std::binary_search (maxV->begin(), maxV->end(), remain)){
data d{itr,remain};
if (minV==&B) std::swap(d.first,d.second);
output.push_back(d);
}
}
if (minV==&B) std::reverse(output.begin(),output.end());
}
int main() {
size_t nb(0);
scanf("%lu",&nb);
for (size_t i=0;i<nb;++i){
size_t a,b(0);
int total(0);
scanf("%lu %lu %d",&a,&b,&total);
std::vector<int> A,B;
for (size_t i=0;i<a;++i){
int aux;
scanf("%d",&aux);
A.push_back(aux);
}
for (size_t i=0;i<b;++i){
int aux;
scanf("%d",&aux);
B.push_back(aux);
}
std::vector<data> output;
search_pairs(A, B, total, output);
auto itr=std::begin(output);
if (itr==std::end(output)) printf("-1");
while (itr!=std::end(output)){
printf("%d %d",(*itr).first, (*itr).second);
if (++itr!=std::end(output)) printf(", ");
}
printf("\n");
}
//code
return 0;
}