[英]Finding a Prime Numbers
我有一個長度為N=10^5
的數組,每個索引1 <= i <= n
我必須計算A[j]-A[i] and (ji) 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)
首先,我將重述您的問題,以便說出我相信您想要實現的目標。 您可能正在尋找形式為A[j]-A[i]
,其中(ji)
是“正”素數且1<=i<j<=N
考慮到這一點...
我們計算將A[k]
加到總和(用p
表示)的次數, A[k]
從總和減去A[k]
(用m
表示)的次數。 好吧, m
等於區間[1,Nk]
的素數,而p
等於區間[1,k-1]
的素數。 如果您不相信我,請逐步模擬代碼的功能。 然后,您可以執行以下操作:
S = 0
for k = 1 to N do
S = S + (p(k) - m(k)) * A[k]
endfor
現在,我們需要找到一種方法來有效確定間隔[1,N]
每個k
p
和m
。 我看到您已經構建了看似素數的有序列表。 因此,要回答“間隔[1,t]
多少個素數?”形式的查詢。 您可以在該列表上對t
執行二進制搜索。 這將使復雜度降低到O(N*log(prime.size))
。
或者,您可以預先計算“間隔[1,t]
多少個素數?”形式的查詢答案。 您需要一個大小為N
的額外數組nrPrimesLessThan
來保留結果,進行如下操作以計算其值:
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)
步驟。 總的來說,線性時間為N
從您的代碼示例判斷,您想要對數組中所有值對的差值求和,而這些值對的索引差為質數。 您已經有了素數的數組。
下圖顯示了如何減去和添加元素:
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)。
這個問題也與素數無關。 上面的方法適用於所有條件差的和,其中索引的差必須包含在一組特定的數字中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.