【问题标题】:Given two arrays a and b .Find all pairs of elements (a1,b1) such that a1 belongs to Array A and b1 belongs to Array B whose sum a1+b1 = k给定两个数组 a 和 b。找到所有元素对 (a1,b1),使得 a1 属于数组 A,b1 属于数组 B,其和 a1+b1 = k
【发布时间】:2010-09-28 16:51:58
【问题描述】:

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

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

我能够提出 O(n log n) 方法,我们将对数组中的一个进行排序,比如 A 并且对于数组 B 中的每个元素 b,在排序后的数组 A 上进行二进制搜索以获取值 (K-b) .

我们可以进一步改进它吗?

【问题讨论】:

  • 这可能是您可以获得的最快的通用解决方案,因为在已排序数组中寻找 n 次的常数因子低于对长度为 n 的未排序数组进行排序的常数因子,通常.因此,您可能只想对一个数组(短数组)进行排序。
  • 如果a = {3, 3}、b = {7, 7}和k = 10,预期输出是多少?

标签: algorithm set


【解决方案1】:

如果数组已排序,您可以在线性时间和常量存储中进行。

  • 从两个指针开始,一个指向 A 的最小元素,另一个指向 B 的最大元素。
  • 计算指向元素的总和。
  • 如果它小于 k,则将指针增加到 A,使其指向下一个最大元素。
  • 如果它大于 k,则将指针递减到 B 中,使其指向下一个最小元素。
  • 如果它正好是 k,那么你已经找到了一对。移动其中一个指针并继续寻找下一对。

如果数组最初是未排序的,那么您可以先对它们进行排序,然后使用上述算法。您可以使用几种不同的方法对它们进行排序,具体取决于您期望的数据类型:

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

【讨论】:

  • 找到所有对还是只找到第一对?
  • 找到一对后,继续增加 A 中的指针,该过程继续进行,直到找到另一对。
  • 我想到了这个解决方案,但即使有两个指针,我也无法避免完全迭代两个数组,因为我需要所有条件都成立的对。我正确吗?
  • 如果已排序,则每个指针将始终向前 (A) 或向后 (B) :2*n 移动最大,所以它是线性的。
  • 看起来很直观,但是你能证明这个算法的正确性吗?
【解决方案2】:

如果您对最大可能数量有限制(我们将其命名为 M),那么您可以在 O(M+n) 中找到解决方案。

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

如果您使用哈希映射而不是大数组,则可以改进它。但我不会认为在这类问题中,hash-map 是一种作弊。

无论如何它会给你 O(n) 的插入,然后 O(n) 的查询,总共 O(n)。

编辑:

这可能有用的一种情况。

  • 您有大小为 10^6 的未排序向量,因此对它们进行排序和匹配的时间为 O(n log n),n = 10^6。
  • 您需要执行此操作 10^6 次(不同的向量),复杂度为 O(n*n*log n)。
  • 最大值为 10^9。

使用我的想法不是布尔值而是整数(每次运行时递增)会给你一个复杂度:

  • "O(10^9)" 创建数组(同样的空间复杂度)
  • 每次运行 O(n),因此总共 O(n*n)。

您正在使用更多空间,但在这种情况下您将速度提高了 log(n) ~=20 倍!

【讨论】:

  • +1 表示第一个可行的解决方案。但是空间复杂度是 M(最大可能数)而不是 n 的函数,在现实世界中分配这么多空间是不可接受的。
  • 是的,我知道。但这取决于M是什么。如果所有值都在 1 到 1000 之间,但每个数组中有 1000 000 个(未排序),那么使用它会很有效。取决于问题;)
  • 你为什么会考虑 hashtable - 作弊?您可以在 10 分钟内编写临时实现(如果没有可用的标准)并获得线性时间和空间复杂度。似乎是最佳解决方案。无论如何,+1 提及它。
  • 哈希表是“作弊”,因为它没有改善大 O,但由于平均/典型情况,似乎对天真的观众有所改善。
【解决方案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 };

【讨论】:

    【解决方案4】:
    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;
    }
    

    【讨论】:

      【解决方案5】:

      我使用了 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;
      }
      

      【讨论】:

        猜你喜欢
        • 2013-08-05
        • 1970-01-01
        • 2013-07-15
        • 1970-01-01
        • 1970-01-01
        • 2018-08-03
        • 1970-01-01
        • 1970-01-01
        • 2021-06-02
        相关资源
        最近更新 更多