[英]Find the sum of all the primes below two million.My program doesn't work for very big numbers
[英]Program to find all primes in a very large given range of integers
我在編程網站上遇到了以下問題:彼得想為其密碼系統生成一些質數。 救救他! 您的任務是生成兩個給定數字之間的所有素數!
輸入項
輸入以一行中的測試用例數t開始(t <= 10)。 在接下來的每條t行中,有兩個數字m和n(1 <= m <= n <= 1000000000,nm <= 100000)用空格隔開。
我想出了以下解決方案:
import java.util.*;
public class PRIME1 {
static int numCases;
static int left, right;
static boolean[] initSieve = new boolean[32000];
static boolean[] answer;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
numCases = sc.nextInt();
initSieve[0] = true;
initSieve[1] = true;
Sieve();
for (int j = 0; j < numCases; j++) {
String line = sc.next();
String line2 = sc.next();
left = Integer.parseInt(line);
right = Integer.parseInt(line2);
answer = new boolean[right - left + 1];
getAnswer();
for (int i = 0; i < answer.length; i++) {
if (!answer[i]) {
int ans = i + left;
System.out.println(ans);
}
}
System.out.println();
}
}
public static void Sieve() {
for (int i = 2; i < 32000; i++) {
if (!initSieve[i]) {
for (int j = 2 * i; j < 32000; j += i) {
initSieve[j] = true;
}
}
if (i * i > 32000)
break;
}
}
public static void getAnswer() {
for (int i = 2; i < 32000 && i <= right; i++) {
if (!initSieve[i]) {
int num = i;
if (num * 2 >= left) {
num *= 2;
} else {
num = (num * (left / num));
if (num < left)
num += i;
}
for (int j = num; j >= left && j <= right; j += i) {
answer[j - left] = true;
}
}
}
}
}
閱讀一些建議后,我已經編輯了解決方案。 我仍然收到超過時間限制的錯誤。 還有其他建議如何進一步優化嗎? 我計算直到32000的所有素數,然后使用這些素數找到n到m之間的素數。
謝謝羅希特
給你
1 <= m <= n <= 1000000000,nm <= 100000
這些是非常小的數字。 要篩選上限為n
的范圍,需要將素數設為√n
。 在這里,您知道n <= 10^9
,所以√n < 31623
,因此您最需要的質數為31621。有3401。您可以在幾微秒內用標准篩生成它們。
然后,您可以通過標記以前篩過的質數的倍數來簡單篩選m
到n
的小范圍,當質數超過√n
時停止。 通過從篩子中消除一些小質數的倍數可以提高速度,但是邏輯變得更加復雜(您需要特別對待小m
篩子)。
public int[] chunk(int m, int n) {
if (n < 2) return null;
if (m < 2) m = 2;
if (n < m) throw new IllegalArgumentException("Borked");
int root = (int)Math.sqrt((double)n);
boolean[] sieve = new boolean[n-m+1];
// primes is the global array of primes to 31621 populated earlier
// primeCount is the number of primes stored in primes, i.e. 3401
// We ignore even numbers, but keep them in the sieve to avoid index arithmetic.
// It would be very simple to omit them, though.
for(int i = 1, p = primes[1]; i < primeCount; ++i) {
if ((p = primes[i]) > root) break;
int mult;
if (p*p < m) {
mult = (m-1)/p+1;
if (mult % 2 == 0) ++mult;
mult = p*mult;
} else {
mult = p*p;
}
for(; mult <= n; mult += 2*p) {
sieve[mult-m] = true;
}
}
int count = m == 2 ? 1 : 0;
for(int i = 1 - m%2; i < n-m; i += 2) {
if (!sieve[i]) ++count;
}
int sievedPrimes[] = new int[count];
int pi = 0;
if (m == 2) {
sievedPrimes[0] = 2;
pi = 1;
}
for(int i = 1 - m%2; i < n-m; i += 2) {
if (!sieve[i]) {
sievedPrimes[pi++] = m+i;
}
}
return sievedPrimes;
}
使用BitSet
或任何其他類型的打包標志數組將減少內存使用,因此由於具有更好的緩存局部性,因此可以顯着提高速度。
使用BitSet而不是布爾數組。
public static BitSet primes (final int MAX)
{
BitSet primes = new BitSet (MAX);
// make only odd numbers candidates...
for (int i = 3; i < MAX; i+=2)
{
primes.set(i);
}
// ... except no. 2
primes.set (2, true);
for (int i = 3; i < MAX; i+=2)
{
/*
If a number z is already eliminated (like 9),
because it is itself a multiple of a prime
(example: 3), then all multiples of z (9) are
already eliminated.
*/
if (primes.get (i))
{
int j = 3 * i;
while (j < MAX)
{
if (primes.get (j))
primes.set (j, false);
j += (2 * i);
}
}
}
return primes;
}
你有沒有到存儲結果數組中? 計算給定整數是否為質數並僅針對{left,left+1,...,right}
每個數字調用它的方法怎么樣?
訪問isNotPrime數組時,始終可以使用偏移量。
給定m,n:
boolean[] isNotPrime = new boolean[n-m+1];
// to now if number x is primer or not
boolean xIsPrime = isNotPrime[x-m];
這里m是偏移量。
您不必強制擁有一個大數組:您可以保留到目前為止找到的素數的列表,並使用多個數組進行測試,這些數組的值= array_slot + offset(已經測試過的值)。 一旦完成從i到j的值,就將ji添加到offset並從J開始的新數組。
您可以從數組中刪除偶數,這樣可以節省一些空間(值= array_slot * 2-1)。
由於m和n之間的距離相對較小,因此您可以蠻力使用m和n之間的每個數字進行快速素數測試算法。
如果允許概率算法,則可以使用Miller-Rabin檢驗 。 令M = nm <= 10 ^ 5且N = n <= 10 ^ 9。 蠻力算法的復雜度為O(k M(log N)^ 3),其中k是一個控制概率保證的常數(對於實際應用,k可以設置為10)。
對於問題的局限性,此復雜度約為10 ^ 9。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.