So, here is a Hackerearth question, regarding (more or less) counting the number of primes between a given pair of numbers (up to 106).
Then there were 3 major options available to me:
- Trial division method, and its variants.
- Sieve of Eratosthenes
- Segmented sieve of Eratosthenes.
As learned from this answer.
The naive method trial division, and its variants gave "Time Limit Exceeded" errors for about 70 % test cases.
Both the Sieve of Eratosthenes and its segmented version gave "Time Limit Exceeded" error for 60 % of the test cases.
Here is my code :
import java.util.* ;
import java.io.BufferedReader ;
import java.io.InputStreamReader ;
/*
Trial division : failed. 6 points
Sieve of Eratosthenes : failed 8 points.
Segmented sieve of Eratosthenes : failed. 8 points.
*/
public class MoguLovesNumbers
{
public static void main(String args[]) throws Exception
{
BufferedReader bro = new BufferedReader(new InputStreamReader(System.in)) ;
int T = Integer.parseInt(bro.readLine()) ;
for(int t=0;t<T;t++)
{
String[] S = bro.readLine().split(" ") ;
int l = Integer.parseInt(S[0]) ;
int r = Integer.parseInt(S[1]) ;
int temp = l<r?l:r ;
r = l<r?r:l ;
l = temp ;
System.out.println(segmentedSieve(l,r)) ;
}
}
static void sieveOfEratosthenes(int l,int r,List<Integer> prime)
{
boolean[] mark = new boolean[r+1] ;
int counter = 0 ;
Arrays.fill(mark,true ) ;
for(int i=2;i<r+1;i++)
{
if(mark[i])
{
if(i>=l)
{
prime.add(i) ;
counter++ ;
}
for(int j=i*2;i*i<=r && j<r+1;j+=i)
mark[j] = false ;
}
}
// return counter ;
}
static int segmentedSieve(int l,int n)
{
int limit = (int)Math.sqrt(n)+1 ;
List<Integer> prime = new ArrayList<Integer>() ;
sieveOfEratosthenes(0,limit,prime) ;
int low = limit ;
int high = limit*2 ;
int count = 0 ;
while(low<n)
{
if(high>n)
high = n ;
boolean mark[] = new boolean[limit+1] ;
Arrays.fill(mark,true ) ;
for(int i=0;i<prime.size();i++)
{
int loLim = (int)(Math.ceil((float)low/prime.get(i)))*prime.get(i) ;
for(int j=loLim;j<=high;j+=prime.get(i))
{
mark[j-low] = false ;
}
}
for(int i = 0;i<mark.length;i++)
if(mark[i] && (i+low>=l)&& (i+low<=high))
{
count++ ;
}
low+=limit ;
high+=limit ;
}
if(l<=Math.sqrt(n)+1)
{
for(int i=0;i<prime.size();i++)
if(prime.get(i)>=l)
count++ ;
}
return count ;
}
}
SUBMISSIONS:
Question:
How can this code be made more efficient? The Segmented Sieve and Simple Sieve both run in O(N log(log(N)))
time.