Algorithm 给定两个数组a和b。查找所有元素对(a1,b1),使a1属于数组a,b1属于数组b,其和为a1+;b1=k

Algorithm 给定两个数组a和b。查找所有元素对(a1,b1),使a1属于数组a,b1属于数组b,其和为a1+;b1=k,algorithm,set,Algorithm,Set,我正在寻找以下算法的解决方案,时间和空间复杂度最小 给定两个数组a和b,查找所有元素对(a1,b1),使a1属于数组a,b1属于数组b,其和a1+b1=k(任意整数) 我提出了O(nlogn)方法,我们将对数组中的一个进行排序,比如A,对数组b中的每个元素b,对排序后的数组A进行二进制搜索,查找值(K-b) 我们可以进一步改进吗?如果你对最大可能数有限制(让我们命名为M),那么你可以在O(M+n)中找到一个解决方案 false的布尔数组,并将A元素的所有值标记为true。然后,对于b元素的每个b

我正在寻找以下算法的解决方案,时间和空间复杂度最小

给定两个数组a和b,查找所有元素对(a1,b1),使a1属于数组a,b1属于数组b,其和a1+b1=k(任意整数)

我提出了O(nlogn)方法,我们将对数组中的一个进行排序,比如A,对数组b中的每个元素b,对排序后的数组A进行二进制搜索,查找值(K-b)


我们可以进一步改进吗?

如果你对最大可能数有限制(让我们命名为M),那么你可以在O(M+n)中找到一个解决方案

false的布尔数组,并将A元素的所有值标记为true。然后,对于b元素的每个b,检查元素编号K-b是否标记为true

如果使用哈希映射而不是大数组,则可以对其进行改进。但我不认为在这样的问题中哈希图是一种作弊。< /P> 无论如何,它会给你O(n)用于插入,然后O(n)用于查询,总共O(n)

编辑:

这可能有用的一种情况

  • 您有大小为10^6的未排序向量,因此对它们进行排序并进行匹配是在O(n log n)中,n=10^6
  • 这个操作需要执行10^6次(不同的向量),复杂度为O(n*n*logn)
  • 最大值为10^9
使用“我的想法”(不是布尔值,而是整数)(每次运行时递增)会使您的复杂性达到:

  • “O(10^9)”来创建数组(同样复杂的空间)
  • O(n)在每次运行时,因此O(n*n)表示总数

您正在使用更多的空间,但在这种情况下,您的速度增加了一个系数log(n)~=20

如果对数组进行排序,则可以在线性时间和恒定存储中进行排序

  • 从两个指针开始,一个指向A的最小元素,另一个指向B的最大元素
  • 计算指向的元素的总和
  • 如果小于k,则将指针增加到A中,使其指向下一个最大的元素
  • 如果大于k,则将指针减为B,使其指向下一个最小的元素
  • 如果正好是k,你就找到了一对。移动其中一个指针,继续寻找下一对指针
如果数组最初未排序,则可以先对其排序,然后使用上述算法。根据您期望的数据类型,您可以使用几种不同的排序方法:

  • 比较排序,如or
比较排序平均需要O(n logn)时间。最后两个比O(n log(n))快,但如果输入数组中的可能值范围非常大,则可能不实用。

template
std::vector>
寻找配对(
标准::向量const&a,标准::向量const&b,T const&k){
std::vector>匹配;
std::sort(a.begin(),a.end());//O(a*lga)
std::sort(b.begin(),b.end());//O(b*lg b)
typename std::vector::常量迭代器acit=a.begin();
typename std::vector::const_reverse_迭代器bcit=b.rbegin();
对于(;acit!=a.end();/*内部*/){
对于(;bcit!=b.rend();/*内部*/){
const T sum=*acit+*bcit;
如果(总和=k){
匹配。推回(std::pair(*acit,*bcit));
++acit;
++bcit;
}
else if(总和k
++bcit;
}
}
}//O(A+B)
返回比赛;
}

我将创建一个包含一个数组元素的哈希表,然后迭代另一个数组查找
k-a(n)
,如果查找成功,将生成一个输出元素。这将使用O(n)空间和时间

在C#中,可能是这样的:

var bSet=newhashset(B);
var结果=来自a中的a
设b=k-a
其中b集包含(b)
选择新的{a,b};

我使用C++,它似乎给了我想要的结果。希望这就是你想要的

使用名称空间std;
使用data=std::pair;
无效搜索对(std::vector&A、std::vector&B、const int total、std::vector&output){
std::sort(A.begin(),A.end(),[](const int i,const int j)->bool{return(ibool{return(aB.size()){minV=&B;maxV=&A;}
else{minV=&A;maxV=&B;}
用于(自动和itr:(*minV)){
自动保留(总itr);
if(std::binary_search(maxV->begin(),maxV->end(),resident)){
数据d{itr,remaine};
if(minV==&B)std::swap(d.first,d.second);
输出。推回(d);
}
}
if(minV==&B)std::reverse(output.begin(),output.end());
}
int main(){
尺寸(0);
扫描频率(“%lu”、&nb);

对于(size_t i=0;i是否查找所有对,或仅查找第一对?一旦找到一对,则通过增加A中的指针继续,过程将继续,直到找到另一对。我想到了这个解决方案,但即使有两个指针,我也无法避免在两个数组上完全迭代,因为我需要所有条件为真的对.我说的对吗?如果对它进行排序,那么每个指针将始终向前(A)或向后(B):2*n移动最大值,因此它是线性的。这看起来很直观,但你能证明这个算法的正确性吗?+1对于第一个可行的解来说。但是空间复杂度是M(最大可能数)的函数而不是N,在现实世界中分配这么多空间是不可接受的。是的,我知道。但是这取决于M是什么。如果所有的值都在1到1000之间,但是每个数组中有1000个000(未排序),那么使用它是有效的。取决于问题;为什么要考虑哈希表-C?