寻找素数

时间:2015-11-21 10:59:20

标签: java algorithm

我有一个长度N=10^5的数组对于每个索引1< = i< = n

我必须计算A[j]-A[i] and (j-i) is prime and j>i

之间的差异

这是我的代码:

for(int i=1;i<=n;i++){

    for(int j=0;j<prime.size();j++){

         int x = prime.get(j);

         if(x+i>n) break;
         ans+= A[x+i]-A[i];
    }
}

我应该如何更快地完成这项工作?我认为时间复杂度是 O(N * prime.size)

2 个答案:

答案 0 :(得分:1)

首先,我会重新解释你的问题,以便说出我认为你想要实现的目标。您可能正在查找A[j]-A[i]形式的差异总和,其中(j-i)是&#34;正面&#34;素数和1<=i<j<=N。记住这句话......

我们计算A[k]添加到总和(由p表示)的次数以及从总和中减去A[k]的次数(由{{1}表示})。好吧,m等于区间m中的素数数量,而[1,N-k]等于区间p中的素数数量。如果您不相信我,请逐步模拟您的代码所做的事情。然后你可以这样做:

[1,k-1]

现在,我们需要找到一种方法来有效地为S = 0 for k = 1 to N do S = S + (p(k) - m(k)) * A[k] endfor 区间中的每个p确定mk。我看到你已经构建了一个似乎是有序的素数列表。那么,要回答一个表格的查询&#39;区间[1,N]中有多少素数?&#39;您可以在[1,t]的列表上执行二进制搜索。这会使复杂性降至t

作为替代方案,您可以预先计算表单查询的答案&#39;区间O(N*log(prime.size))中有多少素数?&#39;。你需要一个大小为[1,t]的额外数组nrPrimesLessThan来保存结果,做这样的事情来计算它的值:

N

预计算部分采用count = 0 for i = 1 to N do if i < prime.get(count) then nrPrimesLessThan[i] = count else count = count + 1 nrPrimesLessThan[i] = count endif endfor 个步骤,但现在一个查询需要O(N)个步骤,因此计算总和需要O(1)个步骤。总体而言,线性时间为O(N)

答案 1 :(得分:0)

从您的代码示例来看,您希望将数组中所有值对的差异求和,其中索引的差异为素数。你已经有了一系列素数。

下图显示了如何减去和添加元素:

        0   1   2   3   4   5   6   7   8   9

        -       +   +       +       +                0
            -       +   +       +       +            1
                -       +   +       +       +        2
                    -       +   +       +            3
                        -       +   +       +        4
                            -       +   +            5
                                -       +   +        6
                                    -       +        7
                                        -            8
                                            -        9

+表示将元素添加到总和中。 -表示从总和中减去元素。这不是一个减法;对于左侧的每次加法都会发生减法,因此将A[0]减去4次。永远不会添加。

另一方面,A[9]永远不会被减去,但会增加四次。通常,每个元素的减去次数与行中的加号相同,并且添加的次数与列中的加号相同。这里有一个对称性:

add[i] = sub[N - i - 1]

表示从零开始的指数。 add[i]的价值是多少?它是小于或等于i的素数的数量。

以下是add数组被称为m的代码示例:

int psum2(const int A[], int n)
{
    int sum = 0;

    int m[n];
    int j = 0;
    int k = 0;

    for (int i = 0; i < n; i++) {
        if (i == prime[j]) {
            k++;
            j++;
        }
        m[i] = k;
    }

    for (int i = 0; i < n; i++) {
        sum += (m[i] - m[n - i - 1])  * A[i];
    }

    return sum;
}

如果您需要更频繁地执行求和,则数组m始终相同并且可以预先计算。算法是O(n)。

问题也与素数的核心无关。上述方法适用于差异的所有条件和,其中索引的差异必须在一组数字中进行处理。