n
の数字が与えられた場合、可能な三角形の総数をどのように見つけることができますか? O(n^3)
時間以内にこれを行うメソッドはありますか?
三角形であるためのa+b>c
、b+c>a
、およびa+c>b
の条件を検討しています。
与えられたnに等しい数がなく、1つの数を複数回使用できると仮定します。たとえば、番号{1,2,3}を指定したので、7つの三角形を作成できます。
これらの仮定のいずれかが当てはまらない場合、アルゴリズムを変更するのは簡単です。
ここでは、最悪の場合にO(n ^ 2)時間を要するアルゴリズムを示します:
2つのペア(i、j1)と(i、j2)j1 <= j2を考えます。 k2((i、j2)のステップ2で見つかりました)> = k1((i、j1)のステップ2が1つ見つかりました)であることは簡単にわかります。これは、jを反復処理し、前のkから始まる数値をチェックするだけでよいことを意味します。したがって、特定のiごとにO(n)時間計算量が得られます。これは、アルゴリズム全体でO(n ^ 2)を意味します。
C++ソースコード:
int Solve(int* a, int n)
{
int answer = 0;
std::sort(a, a + n);
for (int i = 0; i < n; ++i)
{
int k = i;
for (int j = i; j < n; ++j)
{
while (n > k && a[i] + a[j] > a[k])
++k;
answer += k - j;
}
}
return answer;
}
反対票の更新:
これは間違いなくO(n ^ 2)です!償却分析に関するThomasH。Cormenの章(第2版の17.2)を注意深くお読みください。 ネストされたループを数えて複雑さを見つけるのは完全に間違っている場合があります。ここでは、できるだけ簡単に説明しようとしています。 i変数を修正しましょう。次に、そのためにijをiからnに繰り返す必要があります(つまり、O(n)操作)および内部whileループの反復kiからn(これはO(n)操作).注:各jの最初からwhileループを開始しません。また、-から各iに対して実行する必要があります。 to n。したがって、次のようになりますn *(O(n)+ O(n) O( n ^ 2))==。
O(n^2*logn)
には簡単なアルゴリズムがあります。
(a, b, c)
_ここで、_a <= b <= c
_。a + b > c
_だけで十分です(他の不等式は自明に成り立ちます)。そして今:
O(n * logn)
で並べ替えます。例:マージソートによる。(a, b), a <= b
_残りの値c
は少なくともb
であり、_a + b
_未満である必要があります。[b, a+b)
_内のアイテムの数を数える必要があります。これは、a + b(O(logn)
)を二分探索し、b-aであるすべての可能性について_[b,a+b)
_内の項目の数を数えることによって簡単に行うことができます。
すべて一緒にO(n * logn + n^2 * logn)
これはO(n^2 * logn)
です。お役に立てれば。
バイナリソートを使用する場合、それはO(n-log(n))ですよね?二分木を手元に置いて、各ペア(a、b)について、abとc <(a + b)にします。
A、b、cを3辺とします。以下の条件は三角形にも当てはまる必要があります(2つの辺の合計が3番目の辺よりも大きい)
i) a + b > c
ii) b + c > a
iii) a + c > b
以下は三角形を数える手順です。
配列を降順ではない順序で並べ替えます。
2つのポインタ「i」と「j」をそれぞれ1番目と2番目の要素に初期化し、三角形の数を0として初期化します。
「i」と「j」を修正し、「arr [i] + arr [j]> arr [k]」となるように、右端のインデックス「k」(または最大の「arr [k]」)を見つけます。 「arr [i]」と「arr [j]」を2辺として形成できる三角形の数は「k–j」です。三角形の数に「k–j」を追加します。
「arr [i]」を「a」、「arr [j]」をb、「arr [j +1]」と「arr [k]」の間のすべての要素を「c」と見なします。上記の条件(ii)および(iii)は、「arr [i] <arr [j] <arr [k]」で満たされます。そして、「k」を選択するときに条件(i)をチェックします
4.「j」をインクリメントして2番目の要素を再度修正します。
手順3では、以前の値「k」を使用できることに注意してください。理由は簡単です。「arr [i] + arr [j-1]」の値が「arr [k]」より大きいことがわかっている場合は、「arr [i] + arr [j]」と言うことができます。配列は昇順でソートされるため、 'arr [k]'よりも大きくなります。
5.「j」が終わりに達した場合は、「i」をインクリメントします。 「j」を「i + 1」、「k」を「i + 2」として初期化し、手順3と4を繰り返します。
時間計算量: O(n ^ 2)。 3つのネストされたループがあるため、時間の複雑さが増します。アルゴリズムを詳しく見ると、kが最も外側のループで1回だけ初期化されることがわかります。 kはi + 2から始まり、jのすべての値でnまで上がるため、最も内側のループは、最も外側のループの反復ごとに最大でO(n)時間実行されます。したがって、時間計算量はO(n ^ 2)です。
O(n ^ 2 lgn)時間で実行されるアルゴリズムを作成しました。私はそれが正しいと思います...コードはC++で書かれています...
int Search_Closest(A,p,q,n) /*Returns the index of the element closest to n in array
A[p..q]*/
{
if(p<q)
{
int r = (p+q)/2;
if(n==A[r])
return r;
if(p==r)
return r;
if(n<A[r])
Search_Closest(A,p,r,n);
else
Search_Closest(A,r,q,n);
}
else
return p;
}
int no_of_triangles(A,p,q) /*Returns the no of triangles possible in A[p..q]*/
{
int sum = 0;
Quicksort(A,p,q); //Sorts the array A[p..q] in O(nlgn) expected case time
for(int i=p;i<=q;i++)
for(int j =i+1;j<=q;j++)
{
int c = A[i]+A[j];
int k = Search_Closest(A,j,q,c);
/* no of triangles formed with A[i] and A[j] as two sides is (k+1)-2 if A[k] is small or equal to c else its (k+1)-3. As index starts from zero we need to add 1 to the value*/
if(A[k]>c)
sum+=k-2;
else
sum+=k-1;
}
return sum;
}
それが役に立てば幸い........
バイナリ検索を使用して「k」の値を見つけることはできますが、時間計算量が向上します。