所有可能的组合。更快的方式

时间:2011-10-27 20:06:17

标签: c++ performance algorithm

我有一个1到100之间的数字向量(这并不重要),它可以取3到1.000.000之间的大小。

如果有人可以帮助我从该向量中获得3个值唯一*组合。

*独特

示例:我在数组中有以下值:1 [0] 5 [1] 7 [2] 8 [3] 7 [4]([x]是索引)

在这种情况下,1 [0] 5 [1] 7 [2]和1 [3] 5 [1] 7 [4]不同,但1 [0] 5 [1] 7 [2]和7 [ 2] 1 [0] 5 [1]是相同的(重复)

当我使用大量值时,我的算法有点慢(例如1.000.000)。所以我想要的是一种更快的方法。

           for(unsigned int x = 0;x<vect.size()-2;x++){
                for(unsigned int y = x+1;y<vect.size()-1;y++){
                    for(unsigned int z = y+1;z<vect.size();z++)
                    {

                        // do thing with vect[x],vect[y],vect[z]
                    }
                }
            }

6 个答案:

答案 0 :(得分:4)

事实上,你的价值在1到100之间非常重要!因为使用大小为1,000,000的向量,你有很多相同的数字,你不需要检查所有数字!你能做的是以下几点:

注意:以下代码只是一个大纲!它可能缺乏足够的错误检查,只是在这里给你的想法,而不是复制粘贴!

注2:当我写下答案时,我假设数字在[0,99]范围内。然后我读到它们实际上在[1,100]。显然这不是一个问题,你可以-1所有数字,甚至更好,将所有100改为101。

bool exists[100] = {0};  // exists[i] means whether i exists in your vector

for (unsigned int i = 0, size = vect.size(); i < size; ++i)
    exists[vect[i]] = true;

然后,你做的与你之前做的相似:

for(unsigned int x = 0; x < 98; x++)
  if (exists[x])
    for(unsigned int y = x+1; y < 99; y++)
      if (exists[y])
        for(unsigned int z = y+1; z < 100; z++)
          if (exists[z])
          {
            // {x, y, z} is an answer
          }

你可以做的另一件事是花更多的时间准备,以减少产生对的时间。例如:

int nums[100];  // from 0 to count are the numbers you have
int count = 0;

for (unsigned int i = 0, size = vect.size(); i < size; ++i)
{
  bool exists = false;
  for (int j = 0; j < count; ++j)
    if (vect[i] == nums[j])
    {
      exists = true;
      break;
    }
  if (!exists)
    nums[count++] = vect[i];
}

然后

for(unsigned int x = 0; x < count-2; x++)
  for(unsigned int y = x+1; y < count-1; y++)
    for(unsigned int z = y+1; z < count; z++)
    {
      // {nums[x], nums[y], nums[z]} is an answer
    }

让我们将100视为一个变量,所以我们称之为k,并将数组中的实际数字称为m(小于或等于k

使用第一种方法,您可以O(n)准备和O(m^2*k)操作来搜索非常快的值。

在第二种方法中,您有O(nm)准备和O(m^3)来生成值。根据{{​​1}}和n的值,准备时间过长。

你实际上可以合并这两种方法以获得两全其美的效果,所以像这样:

m

然后:

int nums[100];           // from 0 to count are the numbers you have
int count = 0;
bool exists[100] = {0};  // exists[i] means whether i exists in your vector

for (unsigned int i = 0, size = vect.size(); i < size; ++i)
{
  if (!exists[vect[i]])
    nums[count++] = vect[i];
  exists[vect[i]] = true;
}

此方法需要for(unsigned int x = 0; x < count-2; x++) for(unsigned int y = x+1; y < count-1; y++) for(unsigned int z = y+1; z < count; z++) { // {nums[x], nums[y], nums[z]} is an answer } 准备且O(n)费用才能找到唯一的三元组。

编辑:事实证明,对于OP,不同位置的相同数字被视为不同的值。如果确实如此,那我很抱歉,没有更快的解决方案。原因是所有可能的组合本身都是O(m^3)(那是combination)虽然你在C(n, m)中生成了每一个,但它对你来说仍然太大了。

答案 1 :(得分:2)

没有什么可以加速你在那里的循环体。考虑到使用1M矢量大小,您将进行一万亿次循环迭代。

生成这样的所有组合是一个指数问题,这意味着当输入大小变得足够大时,您将无法实际解决它。您唯一的选择是利用您的应用程序的特定知识(您需要的结果,以及它们将如何使用)在可能的情况下“解决”问题。

答案 2 :(得分:0)

可能您可以对输入进行排序,使其唯一,并在a < b < c时选择x [a],x [b]和x [c]。排序为O(n log n),选择组合将为O(n³)。你仍然会有更少的三元组来迭代:

std::vector<int> x = original_vector;
std::sort(x.begin(), x.end());
std::erase(std::unique(x.begin(), x.end()), x.end());
for(a = 0; a < x.size() - 2; ++a)
  for(b=a+1; b < x.size() - 1; ++b)
     for(c=b+1; c< x.size(); ++c
        issue triplet(x[a],x[b],x[c]);

答案 3 :(得分:0)

根据您的实际数据,您可以通过首先制作一个每个值最多包含三个条目的向量并对其进行迭代来显着加快速度。

答案 4 :(得分:0)

正如r15habh指出的那样,我认为数组中的值在1-100 之间的事实实际上非常重要。

这是你可以做的事情:让一个通过数组,将值读入一个唯一的集合。这个本身是O(n)时间复杂度。该集合将不超过100个元素,这意味着O(1)空间复杂度。

既然你需要生成所有3项排列,你仍然需要3个嵌套循环,但是你不是在可能很大的数组上运行,而是在一个最多有100个元素的集合上运行。 / p>

总体时间复杂度取决于您的原始数据集。对于小型数据集,时间复杂度将为O(n ^ 3)。对于大型数据集,它将接近O(n)。

答案 5 :(得分:0)

如果正确理解您的应用程序,则可以使用元组代替,并根据您的要求存储在set或hash表中。如果tri的法线很重要,那么请确保你移动tri以便让我们说最大元素是第一个,如果正常应该无关紧要,那么只需对元组进行排序。一个使用boost&amp; amp;整数:

#include <set>
#include <algorithm>
#include "boost/tuple/tuple.hpp"
#include "boost/tuple/tuple_comparison.hpp"

int main()
{
    typedef boost::tuple< int, int, int > Tri;
    typedef std::set< Tri > TriSet;
    TriSet storage;
    // 1 duplicate
    int exampleData[4][3] = { { 1, 2, 3 }, { 2, 3, 6 }, { 5, 3, 2 }, { 2, 1, 3 } };
    for( unsigned int i = 0; i < sizeof( exampleData ) / sizeof( exampleData[0] ); ++i )    
    {
        std::sort( exampleData[i], exampleData[i] + ( sizeof( exampleData[i] ) / sizeof( exampleData[i][0] ) ) );
        if( !storage.insert( boost::make_tuple( exampleData[i][0], exampleData[i][1], exampleData[i][2] ) ).second )
            std::cout << "Duplicate!" << std::endl;
        else
            std::cout << "Not duplicate!" << std::endl;
    }
}