How to find the pair in an array which have maximum gcd - algorithm

I have to find the the pair in an array which have maximum GCD. I tried different approach but all those solution doesn't run in time, time limit exceed in every solution.
So is there any efficient method to do so.
example =>
Input : arr[] : { 1 2 3 4 5 }
Output : 2
Explanation : Pair {2, 4} has GCD 2 which is highest. Other pairs have a GCD of 1.
I tried these solutions =>
brute force
brute force with Euclidean algorithm
By calculating the frequency of all the divisors of each number present in
the array. And then check which divisor have the frequency greater than 1
from last. (https://www.geeksforgeeks.org/find-pair-maximum-gcd-array)
All above mentioned solution doesn't work.
The link to the question is
https://practice.geeksforgeeks.org/problems/maximum-gcd-pair3534/1

We can use the same logic, divisor occurrence but with a simple optimization. Instead of calculating divisor for each number separately. We will calculate divisors collectively and calculate the answer accordingly. We will traverse each number and then it all multiple till max_element and will keep track of the number of elements for which the current number is the divisor and if the occurrence is greater than 1 we will update our answer. So the solution will be,
int MaxGcd(int n, int a[]) {
int mx = *max_element(a, a + n);
vector<int> cnt(mx + 1, 0);
vector<int> occurrence(mx + 1, 0);
for (int i = 0; i < n; i++) {
occurrence[a[i]]++;
}
int ans = 1;
for (int i = 2; i <= mx; i++) {
for (int j = i; j <= mx; j += i) {
cnt[i] += occurrence[j];
if (cnt[i] > 1) {
ans = i;
}
}
}
return ans;
}

Related

Looking for largest sum inside array

I have a given array [-2 -3 4 -1 -2 1 5 -3] so the largest sum would be 7 (numbers from 3rd to 7th index). This array is just a simple example, the program should be user input elements and length of the array.
My question is, how to determine which sum would be largest?
I created a sum from all numbers and the sum of only positive numbers and yet the positive sum would be great but I didn't used the -1 and -2 after that 3rd index because of the "IF statement" so my sum is 10 and the solution is not good.
I assume your questions is to find the contiguous subarray(containing at least one number) which has the largest sum. Otherwise, the problem is pretty trivial as you can just pick all the positive numbers.
There are 3 solutions that are better than the O(N^2) brute force solution. N is the length of the input array.
Dynamic programming. O(N) runtime, O(N) space
Since the subarray contains at least one number, we know that there are only N possible candidates: subarray that ends at A[0], A[1]...... A[N - 1]
For the subarray that ends at A[i], we have the following optimal substructure:
maxSum[i] = max of {maxSum[i - 1] + A[i], A[i]};
class Solution {
public int maxSubArray(int[] nums) {
int max = Integer.MIN_VALUE;
if(nums == null || nums.length == 0) {
return max;
}
int[] maxSum = new int[nums.length + 1];
for(int i = 1; i < maxSum.length; i++) {
maxSum[i] = Math.max(maxSum[i - 1] + nums[i - 1], nums[i - 1]);
}
for(int i = 1; i < maxSum.length; i++) {
max = Math.max(maxSum[i], max);
}
return max;
}
}
Prefix sum, O(N) runtime, O(1) space
Maintain a minimum sum variable as you iterate through the entire array. When visiting each number in the input array, update the prefix sum variable currSum. Then update the maximum sum and minimum sum shown in the following code.
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int maxSum = Integer.MIN_VALUE, currSum = 0, minSum = 0;
for(int i = 0; i < nums.length; i++) {
currSum += nums[i];
maxSum = Math.max(maxSum, currSum - minSum);
minSum = Math.min(minSum, currSum);
}
return maxSum;
}
}
Divide and conquer, O(N * logN) runtime
Divide the original problem into two subproblems and apply this principle recursively using the following formula.
Let A[0,.... midIdx] be the left half of A, A[midIdx + 1, ..... A.length - 1] be the right half of A. leftSumMax is the answer of the left subproblem, rightSumMax is the answer of the right subproblem.
The final answer will be one of the following 3:
1. only uses numbers from the left half (solved by the left subproblem)
2. only uses numbers from the right half (solved by the right subproblem)
3. uses numbers from both left and right halves (solved in O(n) time)
class Solution {
public int maxSubArray(int[] nums) {
if(nums == null || nums.length == 0)
{
return 0;
}
return maxSubArrayHelper(nums, 0, nums.length - 1);
}
private int maxSubArrayHelper(int[] nums, int startIdx, int endIdx){
if(startIdx == endIdx){
return nums[startIdx];
}
int midIdx = startIdx + (endIdx - startIdx) / 2;
int leftMax = maxSubArrayHelper(nums, startIdx, midIdx);
int rightMax = maxSubArrayHelper(nums, midIdx + 1, endIdx);
int leftIdx = midIdx, rightIdx = midIdx + 1;
int leftSumMax = nums[leftIdx], rightSumMax = nums[rightIdx];
int leftSum = nums[leftIdx], rightSum = nums[rightIdx];
for(int i = leftIdx - 1; i >= startIdx; i--){
leftSum += nums[i];
leftSumMax = Math.max(leftSumMax, leftSum);
}
for(int j = rightIdx + 1; j <= endIdx; j++){
rightSum += nums[j];
rightSumMax = Math.max(rightSumMax, rightSum);
}
return Math.max(Math.max(leftMax, rightMax), leftSumMax + rightSumMax);
}
}
Try this:
locate the first positive number, offset i.
add the following positive numbers, giving a sum of sum, last offset is j. If this sum is greater than your current best sum, it becomes the current best sum with offsets i to j.
add the negative numbers that follow until you get another positive number. If this negative sum is greater in absolute value than sum, start a new sum at this offset, otherwise continue with the current sum.
go back to step 2.
Stop this when you get to the end of the array. The best positive sum has been found.
If no positive sum can be found, locate the least negative value, this single entry would be your best non-trivial sum.

Counting the number of subset solution in the subset sum (knapsack) with dynamic programming

So I want to know how to count all the solutions for a knapsack problem. Namely I'm interested in finding the number of possible subsets from a set of numbers that have the maximum size of K.
e.g we have a set of items of size {3, 2, 5, 6, 7} and the max size is K = 13. So the solutions are {5, 6, 2} and {6, 7}. On the other hand there are two solutions; I want my dynamic programming algorithm to report there are two possible solutions.
This can be done with dynamic programming. The basic strategy is to build a memorization table, d[i][j], which stores the number of combinations using the first j numbers that sum to i. Note that j = 0 represents an empty set of numbers. Here is a sample implementation:
int countCombinations(int[] numbers, int target) {
// d[i][j] = n means there are n combinations of the first j numbers summing to i.
int[][] d = new int[target + 1][numbers.length + 1];
// There is always 1 combination summing to 0, namely the empty set.
for (int j = 0; j <= numbers.length; ++j) {
d[0][j] = 1;
}
// For each total i, calculate the effect of using or omitting each number j.
for (int i = 1; i <= target; ++i) {
for (int j = 1; j <= numbers.length; ++j) {
// "First j numbers" is 1-indexed, our array is 0-indexed.
int number = numbers[j - 1];
// Initialize value to 0.
d[i][j] = 0;
// How many combinations were there before considering the jth number?
d[i][j] += d[i][j - 1];
// How many things summed to i - number?
if (i - number >= 0) {
d[i][j] += d[i - number][j - 1];
}
}
}
// Return the entry in the table storing all the number combos summing to target.
return d[target][numbers.length - 1];
}
Just to add some Google keywords: this problem is also known as summing n coins without repeats to a target sum.
There is a dynamic knapsack solution for this task.In dp array dp[i] stores the number of subsets which their sum is "i". In this case your answer is dp[K].( Sorry for indentation problems I could not figure out how to make it right :( )
dp[0] = 1 ;
for( int i=0; i<N ; i++ )
for( int j=K-a[i] ; j>=0 ; j-- )
dp[j+a[i]] += dp[j]
I don't think Max's algorithm works for the case: [0,0,1] with target of 1. The answer is 4 but his algorithm will output 1. His algorithm only works for positive integers, because it assumes that a sum of 0 can only be achieved with empty set. However, it can also be achieved if 0 exists in the array. The more robust way of tackling this problem (and also more space efficient) is using a 1D dp array. The pseudo-code is the following:
int[] dp = new int[target+1];
for (int num : nums) {
for (int s = target; s >= 0; s--) {
if (s >= num) { // can include num
dp[s] += dp[s-num];
} else { // cannot include num (can be omitted, here for better explanation)
dp[s] += 0;
}
}
}
return dp[target+1];
The reason I backtrack from target to 0 in the inner for loop is to avoid duplication. Think about the example [2,2,2] with target sum of 4. If you iterate from index 0, then you would double count a 2 when you are at dp[4] (should be [1 0 1 0 0] instead of [1 0 1 0 1] after one iteration in inner loop).
Hope this helps.

Dynamic programming based zigzag puzzle

I found this interesting dynamic programming problem where it's required to re-order a sequence of integers in order to maximize the output.
Steve has got N liquor bottles. Alcohol quantity of ith bottle is given by A[i]. Now he wants to have one drink from each of the bottles, in such a way that the total hangover is maximised.
Total hangover is calculated as follow (Assume the 'alcohol quantity' array uses 1-based indexing) :
int hangover=0 ;
for( int i=2 ; i<=N ; i++ ){
hangover += i * abs(A[i] - A[i-1]) ;
}
So, obviously the order in which he drinks from each bottle changes the Total hangover. He can drink the liquors in any order but not more than one drink from each bottle. Also once he starts drinking a liquor he will finish that drink before moving to some other liquor.
Steve is confused about the order in which he should drink so that the hangover is maximized. Help him find the maximum hangover he can have, if he can drink the liquors in any order.
Input Format :
First line contain number of test cases T. First line of each test case contains N, denoting the number of fruits. Next line contain N space separated integers denoting the sweetness of each fruit.
2
7
83 133 410 637 665 744 986
4
1 5 9 11
I tried everything that I could but I wasn't able to achieve a O(n^2) solution. By simply calculating the total hangover over all the permutations has a O(n!) time complexity. Can this problem be solved more efficiently?
Thanks!
My hunch: use a sort of "greedy chaining algorithm" instead of DP.
1) find the pair with the greatest difference (O(n^2))
2) starting from either, find successively the next element with the greatest difference, forming a sort of "chain" (2 x O(n^2))
3) once you've done it for both you'll have two "sums". Return the largest one as your optimal answer.
This greedy strategy should work because the nature of the problem itself is greedy: choose the largest difference for the last bottle, because this has the largest index, so the result will always be larger than some "compromising" alternative (one that distributes smaller but roughly uniform differences to the indices).
Complexity: O(3n^2). Can prob. reduce it to O(3/2 n^2) if you use linked lists instead of a static array + boolean flag array.
Pseudo-ish code:
int hang_recurse(int* A, int N, int I, int K, bool* F)
{
int sum = 0;
for (int j = 2; j <= N; j++, I--)
{
int maxdiff = 0, maxidx;
for (int i = 1; i <= N; i++)
{
if (F[i] == false)
{
int diff = abs(F[K] - F[i]);
if (diff > maxdiff)
{
maxdiff = diff;
maxidx = i;
}
}
}
K = maxidx;
F[K] = true;
sum += maxdiff * I;
}
return sum;
}
int hangover(int* A, int N)
{
bool* F = new bool[N];
int maxdiff = 0;
int maxidx_i, maxidx_j;
for (int j = 2; j <= N; j++, I--)
{
for (int i = 1; i <= N; i++)
{
int diff = abs(F[j] - F[i]);
if (diff > maxdiff)
{
maxdiff = diff;
maxidx_i = i;
maxidx_j = j;
}
}
}
F[maxidx_i] = F[maxidx_j] = true;
int maxsum = max(hang_recurse(A, N, N - 1, maxidx_i, F),
hang_recurse(A, N, N - 1, maxidx_j, F));
delete [] F;
return maxdiff * N + maxsum;
}

Count the subsequences of length 4 divisible by 9

To count the subsequences of length 4 of a string of length n which are divisible by 9.
For example if the input string is 9999
then cnt=1
My approach is similar to Brute Force and takes O(n^3).Any better approach than this?
If you want to check if a number is divisible by 9, You better look here.
I will describe the method in short:
checkDividedByNine(String pNum) :
If pNum.length < 1
return false
If pNum.length == 1
return toInt(pNum) == 9;
Sum = 0
For c in pNum:
Sum += toInt(pNum)
return checkDividedByNine(toString(Sum))
So you can reduce the running time to less than O(n^3).
EDIT:
If you need very fast algorithm, you can use pre-processing in order to save for each possible 4-digit number, if it is divisible by 9. (It will cost you 10000 in memory)
EDIT 2:
Better approach: you can use dynamic programming:
For string S in length N:
D[i,j,k] = The number of subsequences of length j in the string S[i..N] that their value modulo 9 == k.
Where 0 <= k <= 8, 1 <= j <= 4, 1 <= i <= N.
D[i,1,k] = simply count the number of elements in S[i..N] that = k(mod 9).
D[N,j,k] = if j==1 and (S[N] modulo 9) == k, return 1. Otherwise, 0.
D[i,j,k] = max{ D[i+1,j,k], D[i+1,j-1, (k-S[i]+9) modulo 9]}.
And you return D[1,4,0].
You get a table in size - N x 9 x 4.
Thus, the overall running time, assuming calculating modulo takes O(1), is O(n).
Assuming that the subsequence has to consist of consecutive digits, you can scan from left to right, keeping track of what order the last 4 digits read are in. That way, you can do a linear scan and just apply divisibility rules.
If the digits are not necessarily consecutive, then you can do some finangling with lookup tables. The idea is that you can create a 3D array named table such that table[i][j][k] is the number of sums of i digits up to index j such that the sum leaves a remainder of k when divided by 9. The table itself has size 45n (i goes from 0 to 4, j goes from 0 to n-1, and k goes from 0 to 8).
For the recursion, each table[i][j][k] entry relies on table[i-1][j-1][x] and table[i][j-1][x] for all x from 0 to 8. Since each entry update takes constant time (at least relative to n), that should get you an O(n) runtime.
How about this one:
/*NOTE: The following holds true, if the subsequences consist of digits in contagious locations */
public int countOccurrences (String s) {
int count=0;
int len = s.length();
String subs = null;
int sum;
if (len < 4)
return 0;
else {
for (int i=0 ; i<len-3 ; i++) {
subs = s.substring(i, i+4);
sum = 0;
for (int j=0; j<=3; j++) {
sum += Integer.parseInt(String.valueOf(subs.charAt(j)));
}
if (sum%9 == 0)
count++;
}
return count;
}
}
Here is the complete working code for the above problem based on the above discussed ways using lookup tables
int fun(int h)
{
return (h/10 + h%10);
}
int main()
{
int t;
scanf("%d",&t);
int i,T;
for(T=0;T<t;T++)
{
char str[10001];
scanf("%s",str);
int len=strlen(str);
int arr[len][5][10];
memset(arr,0,sizeof(int)*(10*5*len));
int j,k,l;
for(j=0;j<len;j++)
{
int y;
y=(str[j]-48)%10;
arr[j][1][y]++;
}
//printarr(arr,len);
for(i=len-2;i>=0;i--) //represents the starting index of the string
{
int temp[5][10];
//COPYING ARRAY
int a,b,c,d;
for(a=0;a<=4;a++)
for(b=0;b<=9;b++)
temp[a][b]=arr[i][a][b]+arr[i+1][a][b];
for(j=1;j<=4;j++) //represents the length of the string
{
for(k=0;k<=9;k++) //represents the no. of ways to make it
{
if(arr[i+1][j][k]!=0)
{
for(c=1;c<=4;c++)
{
for(d=0;d<=9;d++)
{
if(arr[i][c][d]!=0)
{
int h,r;
r=j+c;
if(r>4)
continue;
h=k+d;
h=fun(h);
if(r<=4)
temp[r][h]=( temp[r][h]+(arr[i][c][d]*arr[i+1][j][k]))%1000000007;
}}}
}
//copy back from temp array
}
}
for(a=0;a<=4;a++)
for(b=0;b<=9;b++)
arr[i][a][b]=temp[a][b];
}
printf("%d\n",(arr[0][1][9])%1000000007);
}
return 0;
}

Segmented Sieve of Eratosthenes?

It's easy enough to make a simple sieve:
for (int i=2; i<=N; i++){
if (sieve[i]==0){
cout << i << " is prime" << endl;
for (int j = i; j<=N; j+=i){
sieve[j]=1;
}
}
cout << i << " has " << sieve[i] << " distinct prime factors\n";
}
But what about when N is very large and I can't hold that kind of array in memory? I've looked up segmented sieve approaches and they seem to involve finding primes up until sqrt(N) but I don't understand how it works. What if N is very large (say 10^18)?
The basic idea of a segmented sieve is to choose the sieving primes less than the square root of n, choose a reasonably large segment size that nevertheless fits in memory, and then sieve each of the segments in turn, starting with the smallest. At the first segment, the smallest multiple of each sieving prime that is within the segment is calculated, then multiples of the sieving prime are marked as composite in the normal way; when all the sieving primes have been used, the remaining unmarked numbers in the segment are prime. Then, for the next segment, for each sieving prime you already know the first multiple in the current segment (it was the multiple that ended the sieving for that prime in the prior segment), so you sieve on each sieving prime, and so on until you are finished.
The size of n doesn't matter, except that a larger n will take longer to sieve than a smaller n; the size that matters is the size of the segment, which should be as large as convenient (say, the size of the primary memory cache on the machine).
You can see a simple implementation of a segmented sieve here. Note that a segmented sieve will be very much faster than O'Neill's priority-queue sieve mentioned in another answer; if you're interested, there's an implementation here.
EDIT: I wrote this for a different purpose, but I'll show it here because it might be useful:
Though the Sieve of Eratosthenes is very fast, it requires O(n) space. That can be reduced to O(sqrt(n)) for the sieving primes plus O(1) for the bitarray by performing the sieving in successive segments. At the first segment, the smallest multiple of each sieving prime that is within the segment is calculated, then multiples of the sieving prime are marked composite in the normal way; when all the sieving primes have been used, the remaining unmarked numbers in the segment are prime. Then, for the next segment, the smallest multiple of each sieving prime is the multiple that ended the sieving in the prior segment, and so the sieving continues until finished.
Consider the example of sieve from 100 to 200 in segments of 20. The five sieving primes are 3, 5, 7, 11 and 13. In the first segment from 100 to 120, the bitarray has ten slots, with slot 0 corresponding to 101, slot k corresponding to 100+2k+1, and slot 9 corresponding to 119. The smallest multiple of 3 in the segment is 105, corresponding to slot 2; slots 2+3=5 and 5+3=8 are also multiples of 3. The smallest multiple of 5 is 105 at slot 2, and slot 2+5=7 is also a multiple of 5. The smallest multiple of 7 is 105 at slot 2, and slot 2+7=9 is also a multiple of 7. And so on.
Function primesRange takes arguments lo, hi and delta; lo and hi must be even, with lo < hi, and lo must be greater than sqrt(hi). The segment size is twice delta. Ps is a linked list containing the sieving primes less than sqrt(hi), with 2 removed since even numbers are ignored. Qs is a linked list containing the offest into the sieve bitarray of the smallest multiple in the current segment of the corresponding sieving prime. After each segment, lo advances by twice delta, so the number corresponding to an index i of the sieve bitarray is lo + 2i + 1.
function primesRange(lo, hi, delta)
function qInit(p)
return (-1/2 * (lo + p + 1)) % p
function qReset(p, q)
return (q - delta) % p
sieve := makeArray(0..delta-1)
ps := tail(primes(sqrt(hi)))
qs := map(qInit, ps)
while lo < hi
for i from 0 to delta-1
sieve[i] := True
for p,q in ps,qs
for i from q to delta step p
sieve[i] := False
qs := map(qReset, ps, qs)
for i,t from 0,lo+1 to delta-1,hi step 1,2
if sieve[i]
output t
lo := lo + 2 * delta
When called as primesRange(100, 200, 10), the sieving primes ps are [3, 5, 7, 11, 13]; qs is initially [2, 2, 2, 10, 8] corresponding to smallest multiples 105, 105, 105, 121 and 117, and is reset for the second segment to [1, 2, 6, 0, 11] corresponding to smallest multiples 123, 125, 133, 121 and 143.
You can see this program in action at http://ideone.com/iHYr1f. And in addition to the links shown above, if you are interested in programming with prime numbers I modestly recommend this essay at my blog.
It's just that we are making segmented with the sieve we have.
The basic idea is let's say we have to find out prime numbers between 85 and 100.
We have to apply the traditional sieve,but in the fashion as described below:
So we take the first prime number 2 , divide the starting number by 2(85/2) and taking round off to smaller number we get p=42,now multiply again by 2 we get p=84, from here onwards start adding 2 till the last number.So what we have done is that we have removed all the factors of 2(86,88,90,92,94,96,98,100) in the range.
We take the next prime number 3 , divide the starting number by 3(85/3) and taking round off to smaller number we get p=28,now multiply again by 3 we get p=84, from here onwards start adding 3 till the last number.So what we have done is that we have removed all the factors of 3(87,90,93,96,99) in the range.
Take the next prime number=5 and so on..................
Keep on doing the above steps.You can get the prime numbers (2,3,5,7,...) by using the traditional sieve upto sqrt(n).And then use it for segmented sieve.
There's a version of the Sieve based on priority queues that yields as many primes as you request, rather than all of them up to an upper bound. It's discussed in the classic paper "The Genuine Sieve of Eratosthenes" and googling for "sieve of eratosthenes priority queue" turns up quite a few implementations in various programming languages.
If someone would like to see C++ implementation, here is mine:
void sito_delta( int delta, std::vector<int> &res)
{
std::unique_ptr<int[]> results(new int[delta+1]);
for(int i = 0; i <= delta; ++i)
results[i] = 1;
int pierw = sqrt(delta);
for (int j = 2; j <= pierw; ++j)
{
if(results[j])
{
for (int k = 2*j; k <= delta; k+=j)
{
results[k]=0;
}
}
}
for (int m = 2; m <= delta; ++m)
if (results[m])
{
res.push_back(m);
std::cout<<","<<m;
}
};
void sito_segment(int n,std::vector<int> &fiPri)
{
int delta = sqrt(n);
if (delta>10)
{
sito_segment(delta,fiPri);
// COmpute using fiPri as primes
// n=n,prime = fiPri;
std::vector<int> prime=fiPri;
int offset = delta;
int low = offset;
int high = offset * 2;
while (low < n)
{
if (high >=n ) high = n;
int mark[offset+1];
for (int s=0;s<=offset;++s)
mark[s]=1;
for(int j = 0; j< prime.size(); ++j)
{
int lowMinimum = (low/prime[j]) * prime[j];
if(lowMinimum < low)
lowMinimum += prime[j];
for(int k = lowMinimum; k<=high;k+=prime[j])
mark[k-low]=0;
}
for(int i = low; i <= high; i++)
if(mark[i-low])
{
fiPri.push_back(i);
std::cout<<","<<i;
}
low=low+offset;
high=high+offset;
}
}
else
{
std::vector<int> prime;
sito_delta(delta, prime);
//
fiPri = prime;
//
int offset = delta;
int low = offset;
int high = offset * 2;
// Process segments one by one
while (low < n)
{
if (high >= n) high = n;
int mark[offset+1];
for (int s = 0; s <= offset; ++s)
mark[s] = 1;
for (int j = 0; j < prime.size(); ++j)
{
// find the minimum number in [low..high] that is
// multiple of prime[i] (divisible by prime[j])
int lowMinimum = (low/prime[j]) * prime[j];
if(lowMinimum < low)
lowMinimum += prime[j];
//Mark multiples of prime[i] in [low..high]
for (int k = lowMinimum; k <= high; k+=prime[j])
mark[k-low] = 0;
}
for (int i = low; i <= high; i++)
if(mark[i-low])
{
fiPri.push_back(i);
std::cout<<","<<i;
}
low = low + offset;
high = high + offset;
}
}
};
int main()
{
std::vector<int> fiPri;
sito_segment(1013,fiPri);
}
Based on Swapnil Kumar answer I did the following algorithm in C. It was built with mingw32-make.exe.
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
const int MAX_PRIME_NUMBERS = 5000000;//The number of prime numbers we are looking for
long long *prime_numbers = malloc(sizeof(long long) * MAX_PRIME_NUMBERS);
prime_numbers[0] = 2;
prime_numbers[1] = 3;
prime_numbers[2] = 5;
prime_numbers[3] = 7;
prime_numbers[4] = 11;
prime_numbers[5] = 13;
prime_numbers[6] = 17;
prime_numbers[7] = 19;
prime_numbers[8] = 23;
prime_numbers[9] = 29;
const int BUFFER_POSSIBLE_PRIMES = 29 * 29;//Because the greatest prime number we have is 29 in the 10th position so I started with a block of 841 numbers
int qt_calculated_primes = 10;//10 because we initialized the array with the ten first primes
int possible_primes[BUFFER_POSSIBLE_PRIMES];//Will store the booleans to check valid primes
long long iteration = 0;//Used as multiplier to the range of the buffer possible_primes
int i;//Simple counter for loops
while(qt_calculated_primes < MAX_PRIME_NUMBERS)
{
for (i = 0; i < BUFFER_POSSIBLE_PRIMES; i++)
possible_primes[i] = 1;//set the number as prime
int biggest_possible_prime = sqrt((iteration + 1) * BUFFER_POSSIBLE_PRIMES);
int k = 0;
long long prime = prime_numbers[k];//First prime to be used in the check
while (prime <= biggest_possible_prime)//We don't need to check primes bigger than the square root
{
for (i = 0; i < BUFFER_POSSIBLE_PRIMES; i++)
if ((iteration * BUFFER_POSSIBLE_PRIMES + i) % prime == 0)
possible_primes[i] = 0;
if (++k == qt_calculated_primes)
break;
prime = prime_numbers[k];
}
for (i = 0; i < BUFFER_POSSIBLE_PRIMES; i++)
if (possible_primes[i])
{
if ((qt_calculated_primes < MAX_PRIME_NUMBERS) && ((iteration * BUFFER_POSSIBLE_PRIMES + i) != 1))
{
prime_numbers[qt_calculated_primes] = iteration * BUFFER_POSSIBLE_PRIMES + i;
printf("%d\n", prime_numbers[qt_calculated_primes]);
qt_calculated_primes++;
} else if (!(qt_calculated_primes < MAX_PRIME_NUMBERS))
break;
}
iteration++;
}
return 0;
}
It set a maximum of prime numbers to be found, then an array is initialized with known prime numbers like 2, 3, 5...29. So we make a buffer that will store the segments of possible primes, this buffer can't be greater than the power of the greatest initial prime that in this case is 29.
I'm sure there are a plenty of optimizations that can be done to improve the performance like parallelize the segments analysis process and skip numbers that are multiple of 2, 3 and 5 but it serves as an example of low memory consumption.
A number is prime if none of the smaller prime numbers divides it. Since we iterate over the prime numbers in order, we already marked all numbers, who are divisible by at least one of the prime numbers, as divisible. Hence if we reach a cell and it is not marked, then it isn't divisible by any smaller prime number and therefore has to be prime.
Remember these points:-
// Generating all prime number up to R
// creating an array of size (R-L-1) set all elements to be true: prime && false: composite
#include<bits/stdc++.h>
using namespace std;
#define MAX 100001
vector<int>* sieve(){
bool isPrime[MAX];
for(int i=0;i<MAX;i++){
isPrime[i]=true;
}
for(int i=2;i*i<MAX;i++){
if(isPrime[i]){
for(int j=i*i;j<MAX;j+=i){
isPrime[j]=false;
}
}
}
vector<int>* primes = new vector<int>();
primes->push_back(2);
for(int i=3;i<MAX;i+=2){
if(isPrime[i]){
primes->push_back(i);
}
}
return primes;
}
void printPrimes(long long l, long long r, vector<int>*&primes){
bool isprimes[r-l+1];
for(int i=0;i<=r-l;i++){
isprimes[i]=true;
}
for(int i=0;primes->at(i)*(long long)primes->at(i)<=r;i++){
int currPrimes=primes->at(i);
//just smaller or equal value to l
long long base =(l/(currPrimes))*(currPrimes);
if(base<l){
base=base+currPrimes;
}
//mark all multiplies within L to R as false
for(long long j=base;j<=r;j+=currPrimes){
isprimes[j-l]=false;
}
//there may be a case where base is itself a prime number
if(base==currPrimes){
isprimes[base-l]= true;
}
}
for(int i=0;i<=r-l;i++){
if(isprimes[i]==true){
cout<<i+l<<endl;
}
}
}
int main(){
vector<int>* primes=sieve();
int t;
cin>>t;
while(t--){
long long l,r;
cin>>l>>r;
printPrimes(l,r,primes);
}
return 0;
}

Resources