简体   繁体   English

为什么这个算法的Big-O N ^ 2 * log N.

[英]Why is the Big-O of this algorithm N^2*log N

Fill array a from a[0] to a[n-1]: generate random numbers until you get one that is not already in the previous indexes. 将数组a从[0]填充到[n-1]:生成随机数,直到得到一个尚未包含在先前索引中的数字。

This is my implementation: 这是我的实施:

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;
}

I thought it was N^2 but it's apparently N^2logN and I'm not sure when the log function is considered. 我以为它是N ^ 2,但它显然是N ^ 2logN,我不确定何时考虑日志功能。

The 0 entry is filled immediately. 0条目立即填写。 The 1 entry has probability 1 - 1 / n = (n - 1) / n of getting filled by a random number. 1条目的概率为1 - 1 / n = (n - 1) / n由随机数填充。 So we need on average n / (n - 1) random numbers to fill the second position. 所以我们需要平均n / (n - 1)随机数来填补第二个位置。 In general, for the k entry we need on average n / (n - k) random numbers and for each number we need k comparisons to check if it's unique. 一般来说,对于k条目,我们需要平均n / (n - k)随机数,对于每个数字,我们需要进行k比较以检查它是否是唯一的。

So we need 所以我们需要

n * 1 / (n - 1) + n * 2 / (n - 2) + ... + n * (n - 1) / 1 n * 1 /(n - 1)+ n * 2 /(n - 2)+ ... + n *(n - 1)/ 1

comparisons on average. 比较平均。 If we consider the right half of the sum, we see that this half is greater than 如果我们考虑总和的右半部分,我们看到这一半大于

n * (n / 2) * (1 / (n / 2) + 1 / (n / 2 - 1) + ... + 1 / 1) n *(n / 2)*(1 /(n / 2)+ 1 /(n / 2 - 1)+ ... + 1/1)

The sum of the fractions is known to be Θ(log(n)) because it's an harmonic series . 已知分数之和为Θ(log(n))因为它是一个谐波系列 So the whole sum is Ω(n^2*log(n)) . 所以总和是Ω(n^2*log(n)) In a similar way, we can show the sum to be O(n^2*log(n)) . 以类似的方式,我们可以将总和显示为O(n^2*log(n)) This means on average we need 这意味着我们平均需要

Θ(n^2*log(n)) Θ(N ^ 2 *的log(n))

operations. 操作。

This is similar to the Coupon Collector problem. 这类似于优惠券收集器问题。 You pick from n items until you get one you don't already have. 你从n个项目中挑选,直到你得到一个你还没有的项目。 On average, you have O(n log n) attempts (see the link, the analysis is not trivial). 平均而言,您有O(n log n)次尝试(请参阅链接,分析并非易事)。 and in the worst case, you examine n elements on each of those attempts. 在最坏的情况下,您会检查每次尝试的n个元素。 This leads to an average complexity of O(N^2 log N) 这导致平均复杂度为O(N ^ 2 log N)

The algorithm you have is not O(n^2 lg n) because the algorithm you have may loop forever and not finish. 你拥有的算法不是O(n^2 lg n)因为你拥有的算法可能永远循环而不是完成。 Imagine on your first pass, you get some value $X$ and on every subsequent pass, trying to get the second value, you continue to get $X$ forever. 想象一下,在你的第一次传球,你得到一些价值$ X $,并在每次后续传球,试图得到第二个值,你继续得到$ X $永远。 We're talking worst case here, after all. 毕竟,我们在这里谈论最糟糕的情况。 That would loop forever. 这将永远循环。 So since your worst case is never finishing, you can't really analyze. 所以,既然你最糟糕的情况永远不会结束,你就无法真正分析。

In case you're wondering, if you know that n is always both the size of the array and the upper bound of the values, you can simply do this: 如果你想知道,如果你知道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;
}

One loop down, one loop back. 一个循环向下,一个循环返回。 O(n) . O(n) Simple. 简单。

If I'm not mistaken, the log N part comes from this part: 如果我没弄错的话,log N部分来自这部分:

for(int i = 0; i < count; i++){
    if(a[i] == rand) isSame = true;
}

Notice that I changed n for count because you know that you have only count elements in your array on each loop. 请注意,我将n更改为count因为您知道每个循环中只有数组中的count元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM