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;
}
}
}
}
目前,对于此挑战的代码高尔夫球版本,我的答案是非高尔夫球版本,仅做了一个小改动:java.util.Random#nextInt(limit)
用于代替(int)(Math.random()*limit)
范围内的整数[0, n)
,因为它的速度大约是它的两倍。
在线尝试。
说明:
使用的方法:
该代码分为两部分:
- 生成一个
n
总数为的随机整数列表n squared
。
- 然后,它会检查所有值是否都是唯一的,并且都不是零;如果任何一个为false,它将再次尝试步骤1,漂洗并重复直到得到结果。
步骤1包含以下子步骤:
1)生成一个n-1
范围为的随机整数数组[0, n squared)
。并添加0
和n squared
到此列表中。这是在O(n+1)
性能上完成的。
2)然后它将使用内置数组对数组进行排序java.util.Arrays.sort(int[])
,这是在O(n*log(n))
性能上完成的,如docs中所述:
将指定的int数组按升序排序。排序算法是一种经过调整的快速排序,它是根据乔恩·本特利(Jon L. Bentley)和道格拉斯·麦克罗伊(M. Douglas McIlroy)的“工程设计排序功能”(软件实践和经验,第1卷,第1期)改编而来的。23(11)P.1249-1265(1993年11月)。该算法在许多数据集上提供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
因此,以上这三个步骤对于性能而言相当不错,这与步骤2和整个过程的循环不同,这是基本的蛮力。步骤2分为以下几个子步骤:
1)差异列表已保存在中java.util.Set
。它将检查此Set的大小是否等于n
。如果是,则表示我们生成的所有随机值都是唯一的。
2)并且还将检查其是否包含0
在Set中,因为质询要求范围为的随机值[1, X]
,其中X
是n squared
减去总和[1, ..., n-1]
,如@Skidsdev在下面的注释中所述。
如果以上两个选项中的任何一个(并非所有值都是唯一的或存在零),它将生成一个新数组,并通过重置为步骤1再次进行设置。这将继续直到获得结果。因此,时间可能相差很大。我看到它在TIO上3秒就能完成n=50
,但在55秒内就能完成n=50
。
均匀性证明:
我不太确定如何证明这一点是完全诚实的。该java.util.Random#nextInt
可以肯定的是统一的,在该文档中描述:
int
从该随机数生成器的序列返回下一个伪随机,均匀分布的值。的一般约定nextInt
是,一个int
值是伪随机生成并返回的。产生(近似)相等概率的所有2 32个可能int
值。
这些(排序的)随机值之间的差异当然不是统一的,但总体而言,这些集合是统一的。同样,我不确定如何用数学方法证明这一点,但是这里有一个脚本,它将10,000
生成的(for n=10
)集放在带有counter的Map中,其中大多数集都是唯一的;一些重复两次;最大重复发生通常在范围内[4,8]
。
安装说明:
由于Java是一种非常知名的语言,其中包含大量有关如何创建和运行Java代码的信息,因此我将在此简短介绍。
我的代码中使用的所有工具都可以在Java 7中使用(也许甚至在Java 5或6中也可以使用,但以防万一,让我们使用7)。我很确定Java 7已经被归档了,所以我建议下载Java 8来运行我的代码。
关于改进的想法:
我想找到一种改进,以检查零,并检查所有值是否唯一。我可以0
通过确保没有添加到数组中的随机值来进行检查,但这将意味着两件事:数组应该是一个,ArrayList
因此我们可以使用内建方法.contains
;应该添加一个while循环,直到我们发现List中还没有的随机值为止。由于检查零与现在做.contains(0)
的设置(这是只检查一次),它是最有可能更好的性能在该点检查,相较于与加入环.contains
上的名单,这将至少被检查n
倍,但很有可能更多。
至于唯一性检查,我们只有n
随机整数的数量n squared
在程序的第1步之后求和,因此只有这样才能检查所有整数是否唯一。可能可以保留一个可排序的List而不是array,并检查它们之间的差异,但是我严重怀疑,与仅将它们放入a Set
并检查Set的大小是否为n
一次相比,它会提高性能。