将数组a从[0]填充到[n-1]:生成随机数,直到得到一个尚未包含在先前索引中的数字。
这是我的实施:
public static int[] first(int n) {
int[] a = new int[n];
int count = 0;
while (count != n) {
boolean isSame = false;
int rand = r.nextInt(n) + 1;
for (int i = 0; i < n; i++) {
if(a[i] == rand) isSame = true;
}
if (isSame == false){
a[count] = rand;
count++;
}
}
return a;
}
我认为它是N ^ 2,但它显然是N ^ 2logN,我不确定何时考虑日志功能。
答案 0 :(得分:34)
立即填写0
条目。 1
条目的概率1 - 1 / n = (n - 1) / n
由随机数填充。因此,我们需要平均n / (n - 1)
个随机数来填补第二个位置。一般来说,对于k
条目,我们需要平均n / (n - k)
个随机数,对于每个数字,我们需要进行k
次比较,以检查它是否唯一。
所以我们需要
n * 1 /(n - 1)+ n * 2 /(n - 2)+ ... + n *(n - 1)/ 1
平均比较。如果我们考虑总和的右半部分,我们会看到这一半大于
n *(n / 2)*(1 /(n / 2)+ 1 /(n / 2 - 1)+ ... + 1/1)
已知分数之和为Θ(log(n))
,因为它是harmonic series。所以总和是Ω(n^2*log(n))
。以类似的方式,我们可以将总和显示为O(n^2*log(n))
。这意味着我们平均需要
Θ(n ^ 2 * log(n))
操作。
答案 1 :(得分:14)
这类似于Coupon Collector问题。你从n个项目中挑选,直到你得到一个你还没有的项目。平均而言,您有O(n log n)次尝试(请参阅链接,分析并非易事)。在最坏的情况下,您会检查每次尝试的n个元素。这导致平均复杂度为O(N ^ 2 log N)
答案 2 :(得分:2)
您拥有的算法不是O(n^2 lg n)
,因为您拥有的算法可能会永远循环而不会完成。想象一下,在你的第一次传球,你得到一些价值$ X $,并在每次后续传球,试图得到第二个值,你继续得到$ X $永远。毕竟,我们在这里谈论最糟糕的情况。这将永远循环。所以,既然你最糟糕的情况永远不会结束,你就无法真正分析。
如果你想知道,如果你知道n
总是数组的大小和值的上限,你可以这样做:
int[] vals = new int[n];
for(int i = 0; i < n; i++) {
vals[i] = i;
}
// fischer yates shuffle
for(int i = n-1; i > 0; i--) {
int idx = rand.nextInt(i + 1);
int t = vals[idx];
vals[idx] = vals[i];
vals[i] = t;
}
一个循环,一个循环返回。 O(n)
。简单。
答案 3 :(得分:-1)
如果我没记错的话,log N部分来自这部分:
for(int i = 0; i < count; i++){
if(a[i] == rand) isSame = true;
}
请注意,我更改了n
的{{1}},因为您知道每个循环中的数组中只有count
个元素。