すべての可能な組み合わせ。より速い方法

私は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
1
1,000,000の値は1,000,000 * 999,999 * 999,998/6の固有の組み合わせを持ちます。これらの組み合わせのそれぞれを即座に取得しても、それらを見るだけで永遠にかかるでしょう!
追加された 著者 Shahbaz,
この例では、インデックス[3]に値8がありませんか?
追加された 著者 Shahbaz,
可能なすべての組み合わせを得るというあなたの目標はありますか? 10 ^ 9の値がある場合は、テストするために10 ^ 27/3の組み合わせになります。何度も高価になるかもしれないと考える
追加された 著者 Brian,
数字が1〜100であることが重要でないということは確かですか?
追加された 著者 r15habh,
1 [0] 5 [1] 7 [2]と1 [3] 5 [1] 7 [4]の違いあなたは絶対に100%確信していますか?もしそうなら、あなたはより良い(単一のスレッドで)得ることができません。
追加された 著者 Mooing Duck,
あなたの例(コードではない)が混乱しています
追加された 著者 KillianDS,

6 答え

実際、あなたの価値は1から100の間であることが非常に重要です!サイズが1,000,000のベクトルでは、等しい数の数字があり、それらのすべてを検査する必要はありません!あなたができることは次のとおりです:

注:次のコードは概要に過ぎません!それは十分なエラーチェックが不足している可能性がありますコピーペーストのためではなく、あなたのアイデアを与えるためだけです!

注2:私が答えを書いたとき、数字は[0、99]の範囲にあると仮定しました。それから私は彼らが実際に[1、100]にいることを読む。明らかに、これは問題ではなく、すべての数字を-1またはそれ以上にすることができ、100から101をすべて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)操作があります。

2番目の方法では、値を生成するために O(nm)準備と O(m ^ 3)があります。 n m の値を考えると、準備に時間がかかります。

あなたは実際には両方の世界のベストを得るために2つの方法をマージすることができます。

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)準備と O(m ^ 3)のコストがあります。

Edit: It turned out that for the OP, the same number in different locations are considered different values. If that is really the case, その後、 I'm sorry, there is no faster solution. The reason is that all the possible combinations themselves are C(n, m) (That's a combination) that although you are generating each one of them in O(1), it is still too big for you.

4
追加された
私はコード内のどこかで愚かな間違いを犯さなかったことを願っています。
追加された 著者 Shahbaz,
ありがとう、私は考えを持っています。
追加された 著者 Sinjuice,

あなたがそこに持っているループ本体をスピードアップするために実行できることは、実際には何もありません。 1Mのベクトルサイズでは、 1兆回回のループ反復を行っているとします。

このようなすべての組み合わせを生成することは指数関数的な問題です。つまり、入力サイズが十分に大きくなったときに実際には解くことができません。あなたの唯一の選択肢は、可能であれば、問題の「回避」を行うために、アプリケーションの特定の知識(結果が必要なもの、その正確な使用方法)を活用することです。

2
追加された
うん、私は今参照してください!
追加された 著者 Shahbaz,
値は0と100の間にあるので、実際には多くを改善できます
追加された 著者 Shahbaz,
これらの3つの値が有効な三角形を作ることができるかどうかを調べるために使用されます(単純なif)
追加された 著者 Sinjuice,
@ Payn3: 1 [0] 5 [1] 7 [2]と1 [3] 5 [1] 7 [4] は実際に異なっていますか?あなたはそうだと言っていましたが、もしあなたが三角形をチェックしているだけなら、彼らは違うでしょう。
追加された 著者 Mooing Duck,
@ Payn3:そして、その三角形が必要...?ここで答えないでください。この種の分析を行うためにコメントに十分な情報を提供する方法はありません。
追加された 著者 Jon,

Possibly you can sort your input, make it unique, and pick x[a], x[b] and x[c] when a < b < c. The sort will be O(n log n) and picking the combination will be O(n³). Still you will have less triplets to iterate over:

std::vector 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]);
0
追加された

実際のデータによっては、最初に各値で最大で3つのエントリを持つベクトルを作成し、それを代わりに反復処理することで、速度を大幅に上げることができます。

0
追加された
私はそれがたくさんの記憶を取ると思うし、それを生成することは彼が現在持っているものとまったく同じくらい速いです。
追加された 著者 Mooing Duck,
どういたしまして。私が提案していたことは、shahbazが何を持っているかと本質的に全く同じです。
追加された 著者 500 - Internal Server Error,

r15habhが指摘しているように、配列の値が1〜100 の間にあるという事実は実際には重要だと思います。

あなたができることは次のとおりです。アレイを1回通過させ、値をユニークなセットに読み込みます。このそれ自体はO(n)時間の複雑さです。この集合は100個以下の要素しか持たないため、O(1)空間の複雑さを意味します。

今度は3つのアイテムの順列を生成する必要があるので、3つのネストされたループが必要ですが、潜在的に巨大な配列で操作するのではなく、最大100個の要素を持つセットで操作します。

Overall time complexity depends on your original data set. For a small data set, time complexity will be O(n^3). For a large data set, it will approach O(n).

0
追加された
彼は、 1 [0] 5 [1] 7 [2]と1 [3] 5 [1] 7 [4]は異なるので、重複する値を削除することはできません。
追加された 著者 Mooing Duck,

If understand your application correctly then you can use a tuple instead, and store in either a set or hash table depending on your requirements. If the normal of the tri matters, then make sure that you shift the tri so that lets say the largest element is first, if normal shouldn't matter, then just sort the tuple. A version using boost & integers:

#include 
#include 
#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;
    }
}
0
追加された
私はあなたの問題を誤解しているようです。
追加された 著者 Ylisar,