Java 7以降、TIOで30秒以内にn = 50
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Random;
class Main{
public static void main(String[] a){
int n=50;
Random randomGenerator = new Random();
int i = n+1;
int squaredN = n*n;
int[]randomIntegers = new int[i];
randomIntegers[n] = squaredN;
while(true){
for(i=n; i-->1; ){
randomIntegers[i] = randomGenerator.nextInt(squaredN);
}
Set<Integer> result = new HashSet<>();
Arrays.sort(randomIntegers);
for(i=n; i-->0; ){
result.add(randomIntegers[i+1] - randomIntegers[i]);
}
if(!result.contains(0) && result.size()==n){
System.out.println(result);
return;
}
}
}
}
Ungolfedバージョンこの問題のコード・ゴルフバージョンのための私の答え一つだけのマイナーな変更となりましたためには、:java.util.Random#nextInt(limit)
の代わりに使用されている(int)(Math.random()*limit)
範囲の整数のために[0, n)
、それは程度なので、早く二回。
オンラインでお試しください。
説明:
使用されるアプローチ:
コードは2つの部分に分かれています。
- のリストを生成する
n
合計がになるランダムな整数量のしn squared
ます。
- 次に、すべての値が一意でゼロがないかどうかをチェックし、どちらかが誤っている場合は、ステップ1を再試行して、結果が得られるまで洗浄して繰り返します。
ステップ1は、次のサブステップで実行されます。
1)n-1
範囲内のランダムな整数の量の配列を生成します[0, n squared)
。0
とn squared
をこのリストに追加します。これはO(n+1)
パフォーマンスで行われます。
2)次に、組み込みjava.util.Arrays.sort(int[])
で配列をソートします。これはO(n*log(n))
、ドキュメントに記載されているように、パフォーマンスで行われます。
指定された整数配列を昇順の数値順にソートします。ソートアルゴリズムは、Jon L. BentleyおよびM. Douglas McIlroyの「Engineering a Sort Function」、Software-Practice and Experience、Vol。23(11)P. 1249-1265(1993年11月)。このアルゴリズムは、他のクイックソートを2次のパフォーマンスに低下させる多くのデータセットでn * log(n)のパフォーマンスを提供します。
3)各ペア間の差を計算します。この結果の差のリストにはn
、合計がになる整数が含まれますn squared
。これはO(n)
パフォーマンスで行われます。
ここに例を示します:
// n = 4, nSquared = 16
// n-1 amount of random integers in the range [0, nSquared):
[11, 2, 5]
// Add 0 and nSquared to it, and sort:
[0, 2, 5, 11, 16]
// Calculate differences:
[2, 3, 6, 5]
// The sum of these differences will always be equal to nSquared
sum([2, 3, 6, 5]) = 16
したがって、上記の3つのステップは、ステップ2や基本的なブルートフォースである全体のループとは異なり、パフォーマンスにかなり優れています。ステップ2は、次のサブステップに分かれています。
1)差分リストはすでにに保存されていjava.util.Set
ます。このセットのサイズがに等しいかどうかをチェックしn
ます。そうであれば、生成したすべてのランダムな値が一意であることを意味します。
2)そしてそれはまた、それが何が含まれていることを確認していないだろう0
課題は範囲内のランダムな値を要求するので、セットでは[1, X]
、X
あるn squared
のマイナス合計が[1, ..., n-1]
で述べたように、@Skidsdev以下のコメントで。
上記の2つのオプションのいずれか(すべての値が一意ではないか、ゼロが存在する場合)は、新しい配列を生成し、手順1にリセットすることによって再度設定します。これは、結果が得られるまで続きます。このため、時間がかなり異なる場合があります。TIOで1回3秒で終了するのを見たn=50
が、55秒で1回終了するn=50
。
均一性の証明:
これが完全に正直であることを証明する方法は完全にはわかりません。java.util.Random#nextInt
ドキュメントに記載されているように、確かに均一です。
int
この乱数ジェネレータのシーケンスから、次の擬似乱数の均一に分散された値を返します。の一般規約でnextInt
は、1つのint
値が擬似ランダムに生成されて返されます。2 32のすべての可能なint
値は、(ほぼ)等しい確率で生成されます。
これらの(ソートされた)ランダム値自体の違いはもちろん均一ではありませんが、セット全体は均一です。繰り返しになりますが、10,000
n=10
これを数学的に証明する方法はわかりませんが、生成されたセット(の)をカウンター付きのMapに配置するスクリプトを次に示します。2回繰り返されるものもあります。また、最大反復回数は通常範囲内[4,8]
です。
インストール手順:
Javaはかなりよく知られている言語であり、Javaコードの作成方法と実行方法に関する情報が豊富にあるため、ここでは短くしておきます。
私のコードで使用されているすべてのツールはJava 7で使用できます(おそらくすでにJava 5または6でも使用されていますが、念のために7を使用しましょう)。Java 7はすでにアーカイブされていると思いますので、コードを実行するためにJava 8をダウンロードすることをお勧めします。
改善に関する考え:
ゼロのチェックの改善を見つけて、すべての値が一意であることを確認したいと思います。私はのためにチェックすることができ0
てください、我々はアレイに追加ランダムな値がそれになっていないが、それは物事のカップルを意味するであろうことで、前に:配列はする必要がありますArrayList
我々は組み込みのメソッドを使用することができるように.contains
。リストにまだないランダムな値が見つかるまで、whileループを追加する必要があります。ゼロのためにチェックすることは、今で行われているので.contains(0)
(一度だけチェックされている)を設定の上、それはパフォーマンスがでループを追加することと比較して、その時点でそれを確認するために、最も可能性の高い方が良いでしょう.contains
、少なくともチェックされます一覧にn
回、しかしおそらくそれ以上。
一意性チェックについては、プログラムのステップ1の後n
で合計されるランダムな整数の量のみがあるn squared
ので、それから初めて、すべてが一意であるかどうかをチェックできます。配列の代わりにソート可能なリストを保持し、その違いを確認することは可能かもしれませんが、単にそれらをaに入れてSet
そのセットのサイズがn
1度かどうかを確認するよりも、パフォーマンスが向上することを真剣に疑っています。