【问题标题】:Combinations of an array algorithm数组算法的组合
【发布时间】:2012-02-19 05:51:22
【问题描述】:

我想找到一个大小为 5 的数组加起来为 15 的组合。这样做的最佳方法是什么。

假设我有数组

7 8 10 5 3

在 C++ 中找到所有加起来为 15 的数字的最佳方法是什么

【问题讨论】:

  • 数组中整数的范围是多少?
  • 虽然可能没有直接回答您的问题,但阅读partitions of an integer 可能会很有趣。
  • 10 是最高的
  • 从示例数据来看,似乎禁止使用负值(和 0)。既然对实现很重要,你应该澄清问题中的条件。

标签: c++ algorithm combinations


【解决方案1】:

如果,正如您在评论中提到的,10 是问题中的最高数字(也是元素的最大数量)。然后蛮力(使用巧妙的位掩码,请参阅this tutorial)会做:

// N is the number of elements and arr is the array.
for (int i = 0; i < (1 << N); ++i) {
    int sum = 0;
    for (int j = 0; j < N; ++j) if (i & (1 << j)) sum += arr[j];
    if (sum == required_sum); // Do something with the subset represented by i.
}

该算法的复杂度为 O(N * 2^N)。请注意,只要 N

但是,如果 N 很大但 N * required_sum 不是很大(高达数百万),则可以使用以下递归(使用动态编程或记忆化):

f(0, 0) = 1
f(0, n) = 0 where n > 0
f(k, n) = 0 where k < 0
f(k + 1, S) = f(k, S - arr[k]) + f(k, S) where k >= 0

其中 f(k, S) 表示通过元素 0..k 的子集获得总和 S 的可能性。动态规划表可用于生成所有子集。生成表格的运行时间是 O(N * S),其中 S 是所需的总和。从表中生成子集的运行时间与此类子集的数量成正比(可能非常大)。

有关问题的一般说明:

一般的问题是NP-Complete。因此,它没有已知的多项式时间算法。然而,它确实有一个pseudo-polynomial time algorithm,即上面的重复。

【讨论】:

    【解决方案2】:

    “最佳”方式取决于您要优化的内容。

    如果数组中的元素不多,有一个简单的组合算法:对于从 1 到 n 的所有长度(其中 n 是数组中的元素数),检查所有可能的 @987654323 集合@ 数字并打印每个数字的总和为 15。

    从实施时间的角度来看,这可能是最好的。从运行时效率的角度来看,动态编程解决方案(这是一个 DP 问题)可能是最好的;这里的 DP 解决方案是 O(N³),组合解决方案远不止于此。

    DP 算法的要点(我不是在编写代码)是遍历您的数组,并跟踪您到目前为止看到的子数组可以得出的所有可能的总和。当您到达每个新的数组元素时,请检查您之前获得的所有部分和并将其添加到它们(不删除原始部分和)。每当有东西达到 15 或超过它时,从您正在跟踪的集合中丢弃该总和(如果它正好达到 15,则打印它)。

    【讨论】:

      【解决方案3】:

      我的建议是递归。

      跟踪baseindex和currentindex 并尝试在每次递归时累积值

      累计值为15时返回当前索引的整数值 else if currentindex 达到 5 且累计值不是 15 返回 0

      当return为0且baseindex仍小于5时,将base index加1,重置当前索引和累加值,再次开始递归。

      【讨论】:

        【解决方案4】:

        对元素的数组进行排序。 维护两个指针,一个在排序数组的开头,另一个在它的末尾。 如果两个元素之和大于 15,则减小第二个指针。 如果总和小于 15,则增加第一个指针。 如果 sum 等于 15,记录这两个元素,并增加第一个指针。

        希望它有效。

        【讨论】:

          【解决方案5】:

          递归是我能想到的一种选择。因为我手头有一些空闲时间,所以我把这个函数放在一起(尽管它可能不必要地大,并且没有优化到极端)。我只用你提供的数字对其进行了测试。

          void getCombinations( std::vector<int>& _list, std::vector<std::vector<int>>& _output, 
                                std::vector<int>& _cSumList = std::vector<int>(), int _sum = 0 )
          {
              for ( std::vector<int>::iterator _it = _list.begin(); _it < _list.end(); ++_it)
              {
                  _sum += *_it;
                  _cSumList.push_back( *_it );
                  std::vector<int> _newList;
                  for ( std::vector<int>::iterator _itn = _list.begin(); _itn < _list.end(); ++_itn )
                      if ( *_itn != *_it )
                          _newList.push_back( *_itn );
                  if ( _sum < 15 )
                      getCombinations( _newList, _output, _cSumList, _sum );
                  else if ( _sum == 15 )
                  {
                      bool _t = false;
                      for ( std::vector<std::vector<int>>::iterator _itCOutputList = _output.begin(); _itCOutputList < _output.end(); ++_itCOutputList )
                      {
                          unsigned _count = 0;
                          for ( std::vector<int>::iterator _ita = _itCOutputList->begin(); _ita < _itCOutputList->end(); ++_ita )
                              for ( std::vector<int>::iterator _itb = _cSumList.begin(); _itb < _cSumList.end(); ++_itb )
                                  if ( *_itb == *_ita )
                                      ++_count;
                          if ( _count == _cSumList.size() )
                              _t = true;
                      }
                      if ( _t == false )
                          _output.push_back( _cSumList );
                  }
                  _cSumList.pop_back();
                  _sum -= *_it;
              }
          }
          

          您的号码的用法示例:

          int _tmain(int argc, _TCHAR* argv[])
          {
              std::vector<int> list;
              list.push_back( 7 );
              list.push_back( 8 );
              list.push_back( 10 );
              list.push_back( 5 );
              list.push_back( 3 );
              std::vector<std::vector<int>> output;
              getCombinations( list, output );
              for ( std::vector<std::vector<int>>::iterator _it = output.begin(); _it < output.end(); ++_it)
              {
                  for ( std::vector<int>::iterator _it2 = (*_it).begin(); _it2 < (*_it).end(); ++_it2)
                      std::cout << *(_it2) << ",";
                  std::cout << "\n";
              }
              std::cin.get();
              return 0;
          }
          

          最佳方式是主观的。正如我所说,上面的代码可以大大改进,但应该给你一个起点。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-29
            • 2011-01-31
            相关资源
            最近更新 更多