I have a program like this: given a sequence of integers, find the biggest prime and its positon.
Example:
input:
9 // how many numbers
19 7 81 33 17 4 19 21 13
output:
19 // the biggest prime
1 7 // and its positon
So first I get the input, store it in an array, make a copy of that array and sort it (because I use a varible to keep track of the higest prime, and insane thing will happen if that was unsorted) work with every number of that array to check if it is prime, loop through it again to have the positon and print the result.
But the time is too slow, can I improve it?
My code:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
int numbersNotSorted[n];
int maxNum{0};
for (int i = 0; i < n; i++)
{
cin >> numbersNotSorted[i];
}
int numbersSorted[n];
for (int i = 0; i < n; i++)
{
numbersSorted[i] = numbersNotSorted[i];
}
sort(numbersSorted, numbersSorted + n);
for (int number = 0; number < n; number++)
{
int countNum{0};
for (int i = 2; i <= sqrt(numbersSorted[number]); i++)
{
if (numbersSorted[number] % i == 0)
countNum++;
}
if (countNum == 0)
{
maxNum = numbersSorted[number];
}
}
cout << maxNum << '\n';
for (int i = 0; i < n; i++)
{
if (numbersNotSorted[i] == maxNum)
cout << i + 1 << ' ';
}
}
If you need the biggest prime, sorting the array brings you no benefit, you'll need to check all the values stored in the array anyway.
Even if you implemented a fast sorting algorithm, the best averages you can hope for are O(N + k), so just sorting the array is actually more costly than looking for the largest prime in an unsorted array.
The process is pretty straight forward, check if the next value is larger than the current largest prime, and if so check if it's also prime, store the positions and/or value if it is, if not, check the next value, repeat until the end of the array.
θ(N) time compexity will be the best optimization possible given the conditions.
Start with a basic "for each number entered" loop:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main() {
int n;
int newNumber;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
}
}
If the new number is smaller than the current largest prime, then it can be ignored.
int main() {
int n;
int newNumber;
int highestPrime;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
if(newNumber >= highestPrime) {
}
}
}
If the new number is equal to the highest prime, then you just need to store its position somewhere. I'm lazy, so:
int main() {
int n;
int newNumber;
int highestPrime;
int maxPositions = 1234;
int positionList[maxPositions];
int nextPosition;
int currentPosition = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
currentPosition++;
if(newNumber >= highestPrime) {
if(newNumber == highestPrime) {
if(nextPosition+1 >= maxPositions) {
// List of positions is too small (should've used malloc/realloc instead of being lazy)!
} else {
positionList[nextPosition++] = currentPosition;
}
}
}
}
}
If the new number is larger than the current largest prime, then you need to figure out if it is a prime number, and if it is you need to reset the list and store its position, etc:
int main() {
int n;
int newNumber;
int highestPrime = 0;
int maxPositions = 1234;
int positionList[maxPositions];
int nextPosition;
int currentPosition = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> newNumber;
currentPosition++;
if(newNumber >= highestPrime) {
if(newNumber == highestPrime) {
if(nextPosition+1 >= maxPositions) {
// List of positions is too small (should've used malloc/realloc instead of being lazy)!
} else {
positionList[nextPosition++] = currentPosition;
}
} else { // newNumber > highestPrime
if(isPrime(newNumber)) {
nextPosition = 0; // Reset the list
highestPrime = newNumber;
positionList[nextPosition++] = currentPosition;
}
}
}
}
}
You'll also want something to display the results:
if(highestPrime > 0) {
for(nextPosition= 0; nextPosition < currentPosition; nextPosition++) {
cout << positionList[nextPosition];
}
}
Now; the only thing you're missing is an isPrime(int n) function. The fastest way to do that is to pre-calculate a "is/isn't prime" bitfield. It might look something like:
bool isPrime(int n) {
if(n & 1 != 0) {
n >>= 1;
if( primeNumberBitfield[n / 32] & (1 << (n % 32)) != 0) {
return true;
}
}
return false;
}
The problem here is that (for positive values in a 32-bit signed integer) you'll need 1 billion bits (or 128 MiB).
To avoid that you can use a much smaller bitfield for numbers up to sqrt(1 << 31) (which is only about 4 KiB); then if the number is too large for the bitfield you can use the bitfield to find prime numbers and check (with modulo) if they divide the original number evenly.
Note that Sieve of Eratosthenes ( https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes ) is an efficient way to generate that smaller bitfield (but is not efficient to use for a sparse population of larger numbers).
If you do it right, you'll probably create the illusion that it's instantaneous because almost all of the work will be done while a human is slowly typing the numbers in (and not left until after all of the numbers have been entered). For a very fast typist you'll have ~2 milliseconds between numbers, and (after the last number is entered) humans can't notice delays smaller than about 10 milliseconds.
But the time is too slow, can I improve it?
Below loop suffers from:
Why check smallest values first? Makes more sense to check largest values first to find the largest prime. Exit the for (... number..) loop early once a prime is found. This takes advantage of the work done by sort().
Once a candidate value is not a prime, quit testing for prime-ness.
.
// (1) Start for other end rather than as below
for (int number = 0; number < n; number++) {
int countNum {0};
for (int i = 2; i <= sqrt(numbersSorted[number]); i++) {
if (numbersSorted[number] % i == 0)
// (2) No point in continuing prime testing, Value is composite.
countNum++;
}
if (countNum == 0) {
maxNum = numbersSorted[number];
}
}
Corrections left for OP to implement.
Advanced: Prime testing is a deep subject and many optimizations (trivial and complex) exist that are better than OP's approach. Yet I suspect the above 2 improvement will suffice for OP.
Brittleness: Code does not well handle the case of no primes in the list or n <= 0.
i <= sqrt(numbersSorted[number]) is prone to FP issues leading to an incorrect results. Recommend i <= numbersSorted[number]/i).
Sorting is O(n * log n). Prime testing, as done here, is O(n * sqrt(n[i])). Sorting does not increase O() of the overall code when the square root of the max value is less than log of n. Sorting is worth doing if the result of the sort is used well.
Code fails if the largest value was 1 as prime test incorrectly identifies 1 as a prime.
Code fails if numbersSorted[number] < 0 due to sqrt().
Simply full-range int prime test:
bool isprime(int num) {
if (num % 2 == 0) return num == 2;
for (int divisor = 3; divisor <= num / divisor; divisor += 2) {
if (num % divisor == 0) return false;
}
return num > 1;
}
If you want to find the prime, don't go for sorting. You'll have to check for all the numbers present in the array then.
You can try this approach to do the same thing, but all within a lesser amount of time:
Step-1: Create a global function for detecting a prime number. Here's how you can approach this-
bool prime(int n)
{
int i, p=1;
for(i=2;i<=sqrt(n);i++) //note that I've iterated till the square root of n, to cut down on the computational time
{
if(n%i==0)
{
p=0;
break;
}
}
if(p==0)
return false;
else
return true;
}
Step-2: Now your main function starts. You take input from the user:
int main()
{
int n, i, MAX;
cout<<"Enter the number of elements: ";
cin>>n;
int arr[n];
cout<<"Enter the array elements: ";
for(i=0;i<n;i++)
cin>>arr[i];
Step-3: Note that I've declared a counter variable MAX. I initialize this variable as the first element of the array: MAX=arr[0];
Step-4: Now the loop for iterating the array. What I did was, I iterated through the array and at each element, I checked if the value is greater than or equal to the previous MAX. This will ensure, that the program does not check the values which are less than MAX, thus eliminating a part of the array and cutting down the time. I then nested another if statement, to check if the value is a prime or not. If both of these are satisfied, I set the value of MAX to the current value of the array:
for(i=0;i<n;i++)
{
if(arr[i]>=MAX) //this will check if the number is greater than the previous MAX number or not
{
if(prime(arr[i])) //if the previous condition satisfies, then only this block of code will run and check if it's a prime or not
MAX=arr[i];
}
}
What happens is this- The value of MAX changes to the max prime number of the array after every single loop.
Step-5: Then, after finally traversing the array, when the program finally comes out of the loop, MAX will have the largest prime number of the array stored in it. Print this value of MAX. Now for getting the positions where MAX happens, just iterate over the whole loop and check for the values that match MAX and print their positions:
for(i=0;i<n;i++)
{
if(arr[i]==MAX)
cout<<i+1<<" ";
}
I ran this code in Dev C++ 5.11 and the compilation time was 0.72s.
Related
I'm trying to write a c++ program which gets an integer n (n>=1 && n<=100000) from the user and puts the sum of its digits into b. The output needed is the b-th prime number coming after n. I'm an absolute beginner in programming so I don't know what's wrong with the for loop or any other code that it doesn't show the correct output. For example the 3rd prime number after 12 (1+2=3) is 19 but the loop counts the prime numbers from 2 instead of 12, so it prints 7 as result.
#include <iostream>
using namespace std;
bool isPrime(int n)
{
if(n <= 1)
return false;
for(int i = 2; i <= (n/2); i++)
if(n % i == 0)
return false;
return true;
}
int main()
{
long int n;
int b = 0;
cin>>n;
while(n >= 1 && n <= 100000){
b += n % 10;
n /= 10;
}
for(int i = n, counter = b; counter <= 10; i++)
if(isPrime(i)){
counter++;
if(i > n)
cout<<counter<<"th prime number after n is : "<<i<<endl;
}
return 0;
}
So one of the possible solutions to my question, according to #Bob__ answer (and converting it to the code style I've used in the initial code) is as follows:
#include <iostream>
using namespace std;
bool isPrime(long int number)
{
if(number <= 1)
return false;
for(int i = 2; i <= (number / 2); i++)
if(number % i == 0)
return false;
return true;
}
int sumOfDigits(long int number)
{
int sum = 0;
while(number >= 1 && number <= 100000)
{
sum += number % 10;
number /= 10;
}
return sum;
}
long int bthPrimeAfter(int counter, long int number)
{
while(counter)
{
++number;
if(isPrime(number))
--counter;
}
return number;
}
int main()
{
long int number;
cin>>number;
int const counter = sumOfDigits(number);
cout<<bthPrimeAfter(counter, number)<<"\n";
return 0;
}
As dratenik said in their comment:
You have destroyed the value in n to produce b in the while loop. When the for loop comes around, n keeps being zero.
That's a key point to understand, sometimes we need to make a copy of a variable. One way to do that is passing it to a function by value. The function argument will be a local copy which can be changed without affecting the original one.
As an example, the main function could be written like the following:
#include <iostream>
bool is_prime(long int number);
// ^^^^^^^^ So is `n` in the OP's `main`
int sum_of_digits(long int number);
// ^^^^^^^^^^^^^^^ This is a local copy.
long int nth_prime_after(int counter, long int number);
int main()
{
long int number;
// The input validation (check if it's a number and if it's in the valid range,
// deal with errors) is left to the reader as an exercise.
std::cin >> number;
int const counter = sum_of_digits(number);
std::cout << nth_prime_after(counter, number) << '\n';
return 0;
}
The definition of sum_of_digits is straightforward.
int sum_of_digits(long int number)
{
int sum = 0;
while ( number ) // Stops when number is zero. The condition n <= 100000
{ // belongs to input validation, like n >= 0.
sum += number % 10;
number /= 10; // <- This changes only the local copy.
}
return sum;
}
About the last part (finding the nth prime after the chosen number), I'm not sure to understand what the asker is trying to do, but even if n had the correct value, for(int i = n, counter = b; counter <= 10; i++) would be just wrong. For starters, there's no reason for the condition count <= 10 or at least none that I can think of.
I'd write something like this:
long int nth_prime_after(int counter, long int number)
{
while ( counter )
{
++number;
if ( is_prime(number) )
{
--counter; // The primes aren't printed here, not even the nth.
}
}
return number; // Just return it, the printing is another function's
} // responsabilty.
A lot more could be said about the is_prime function and the overall (lack of) efficiency of this algorithm, but IMHO, it's beyond the scope of this answer.
The question is:
Ramanujan is so fond of playing number games. One day Ramanujan and Anish played a game. Ramanujan gave Anish a number string and asked him to find all the distinct substrings of size at most six that are prime. Anish being good at maths takes up the game and if he can give solutions to all the input sets Ramanujan provides him, Anish wins the game. Your task is to help Anish win the game.
Input Format
First line contains T, The number of test cases. Each test case contains a string of size N containing only integers.
Constraints
1 <= Number of Test Cases <= 10 1 <= N <= 10^7
Output Format
For Each Test case, print the total number of distinct prime substrings of length at most 6.
My code is in c++:
I had created a vector and map of all the prime number which is less than square root of 10^7 and had intialised map with 1(1 indicates prime number,0 indicates composite number).
Even for checking whether the number is prime or not ,I am dividing it with only prime number less than its square root.
But even doing all this ,I am unable to pass 2nd testcase(showing terminated due to timeout).I am only able to pass 1st test case.I think my program is taking a lot of time to create substrings(using substr() function).Is there any way to reduce time complexity ?plz answer.
map<long int,int>mp{{2,1},{3,1},{5,1},............................,{3121,1},{3137,1}};
map<long int,int>p;
vector<long int>v{2,3,5,..............3137};
long int c=0;
void check_prime(long int n)
{
long int i;
int flag=-1;
for(i=0;v[i]*v[i]<=n;i++)
{
if(n%v[i]==0)
{
flag=1;
break;
}
}
if(flag==-1)
{
++c;
mp.insert(pair<long int,int>(n,1));
p.insert(pair<long int,int>(n,1));
}
else
{
mp.insert(pair<long int,int>(n,0));
p.insert(pair<long int,int>(n,1));
}
}
int main() {
int t;
string s;
long int n,n1,i,j;
cin>>t;
while(t--)
{
long int i,j;
cin>>s;
for(i=0;i<s.length();i++)
{
int l=s.length()-i;
for(j=1;j<=min(6,l);j++)
{
n=stoi(s.substr(i,j));
if(p.count(n)==0)
{
if(mp.count(n)==1 )
{
if(mp[n]==1 )
{
++c;
p.insert(pair<long int,int>(n,1));
}
else
{
p.insert(pair<long int,int>(n,1));
}
}
else
{
if(n<3162 || n%2==0 || n%5==0)
{
mp.insert(pair<long int,int>(n,0));
p.insert(pair<long int,int>(n,1));
}
else
{
check_prime(n);
}
}
}
}
}
cout<<c<<endl;
p.clear();
c=0;
}
return 0;
}
You don't need call check_prime() every time in the loop.
Instead, call it once to save result and use it later on.
Consider Sieve of Eratosthenes:
int np[1000000]; // not prime
int main(void)
{
np[1] = 1;
for (int i = 2; i*i < 1000000; i++)
for (int j = 2; i*j < 1000000; j++)
np[i*j] = 1;
// use np[n].
return 0;
}
Using np[n] will take O(1) as oppose to O(sqrt(n)) before.
I'm making a simple program to calculate the number of pairs in an array that are divisible by 3 array length and values are user determined.
Now my code is perfectly fine. However, I just want to check if there is a faster way to calculate it which results in less compiling time?
As the length of the array is 10^4 or less compiler takes less than 100ms. However, as it gets more to 10^5 it spikes up to 1000ms so why is this? and how to improve speed?
#include <iostream>
using namespace std;
int main()
{
int N, i, b;
b = 0;
cin >> N;
unsigned int j = 0;
std::vector<unsigned int> a(N);
for (j = 0; j < N; j++) {
cin >> a[j];
if (j == 0) {
}
else {
for (i = j - 1; i >= 0; i = i - 1) {
if ((a[j] + a[i]) % 3 == 0) {
b++;
}
}
}
}
cout << b;
return 0;
}
Your algorithm has O(N^2) complexity. There is a faster way.
(a[i] + a[j]) % 3 == ((a[i] % 3) + (a[j] % 3)) % 3
Thus, you need not know the exact numbers, you need to know their remainders of division by three only. Zero remainder of the sum can be received with two numbers with zero remainders (0 + 0) and with two numbers with remainders 1 and 2 (1 + 2).
The result will be equal to r[1]*r[2] + r[0]*(r[0]-1)/2 where r[i] is the quantity of numbers with remainder equal to i.
int r[3] = {};
for (int i : a) {
r[i % 3]++;
}
std::cout << r[1]*r[2] + (r[0]*(r[0]-1)) / 2;
The complexity of this algorithm is O(N).
I've encountered this problem before, and while I don't find my particular solution, you could improve running times by hashing.
The code would look something like this:
// A C++ program to check if arr[0..n-1] can be divided
// in pairs such that every pair is divisible by k.
#include <bits/stdc++.h>
using namespace std;
// Returns true if arr[0..n-1] can be divided into pairs
// with sum divisible by k.
bool canPairs(int arr[], int n, int k)
{
// An odd length array cannot be divided into pairs
if (n & 1)
return false;
// Create a frequency array to count occurrences
// of all remainders when divided by k.
map<int, int> freq;
// Count occurrences of all remainders
for (int i = 0; i < n; i++)
freq[arr[i] % k]++;
// Traverse input array and use freq[] to decide
// if given array can be divided in pairs
for (int i = 0; i < n; i++)
{
// Remainder of current element
int rem = arr[i] % k;
// If remainder with current element divides
// k into two halves.
if (2*rem == k)
{
// Then there must be even occurrences of
// such remainder
if (freq[rem] % 2 != 0)
return false;
}
// If remainder is 0, then there must be two
// elements with 0 remainder
else if (rem == 0)
{
if (freq[rem] & 1)
return false;
}
// Else number of occurrences of remainder
// must be equal to number of occurrences of
// k - remainder
else if (freq[rem] != freq[k - rem])
return false;
}
return true;
}
/* Driver program to test above function */
int main()
{
int arr[] = {92, 75, 65, 48, 45, 35};
int k = 10;
int n = sizeof(arr)/sizeof(arr[0]);
canPairs(arr, n, k)? cout << "True": cout << "False";
return 0;
}
That works for a k (in your case 3)
But then again, this is not my code, but the code you can find in the following link. with a proper explanation. I didn't just paste the link since it's bad practice I think.
I tried a code on a coding website to find the largest prime factor of a number and it's exceeding the time limit for the last test case where probably they are using a large prime number. Can you please help me to reduce the complexity of the following code?
int main()
{
long n;
long int lar, fact;
long int sqroot;
int flag;
cin >> n;
lar=2, fact=2;
sqroot = sqrt(n);
flag = 0;
while(n>1)
{
if((fact > sqroot) && (flag == 0)) //Checking only upto Square Root
{
cout << n << endl;
break;
}
if(n%fact == 0)
{
flag = 1;
lar = fact;
while(n%fact == 0)
n = n/fact;
}
fact++;
}
if(flag == 1) //Don't display if loop fact reached squareroot value
cout << lar << endl;
}
Here I've also taken care of the loop checking till Square Root value. Still, how can I reduce its complexity further?
You can speed things up (if not reduce the complexity) by supplying a hard-coded list of the first N primes to use for the initial values of fact, since using composite values of fact are a waste of time. After that, avoid the obviously composite values of fact (like even numbers).
You can reduce the number of tests by skipping even numbers larger than 2, and stopping sooner if you have found smaller factors. Here is a simpler and faster version:
int main() {
unsigned long long n, lar, fact, sqroot;
cin >> n;
lar = 0;
while (n && n % 2 == 0) {
lar = 2;
n /= 2;
}
fact = 3;
sqroot = sqrt(n);
while (fact <= sqroot) {
if (n % fact == 0) {
lar = fact;
do { n /= fact; } while (n % fact == 0);
sqroot = sqrt(n);
}
fact += 2;
}
if (lar < n)
lar = n;
cout << lar << endl;
return 0;
}
I am not sure how large the input numbers may become, using the larger type unsigned long long for these computations will get you farther than long. Using a precomputed array of primes would help further, but not by a large factor.
The better result I've obtained is using the function below (lpf5()). It's based on the primality() function (below) that uses the formulas 6k+1, 6k-1 to individuate prime numbers. All prime numbers >= 5 may be expressed in one of the forms p=k*6+1 or p=k*6-1 with k>0 (but not all the numbers having such a forms are primes). Developing these formulas we can see a sequence like the following:
k=1 5,7
k=2 11,13
k=3 17,19
k=4 23,25*
k=5 29,31
.
.
.
k=10 59,61
k=11 65*,67
k=12 71,73
...
5,7,11,13,17,19,23,25,29,31,...,59,61,65,67,71,73,...
We observe that the difference between the terms is alternatively 2 and 4. Such a results may be obtained also using simple math. Is obvious that the difference between k*6+1 and k*6-1 is 2. It's simple to note that the difference between k*6+1 and (k+1)*6-1 is 4.
The function primality(x) returns x when x is prime (or 0 - take care) and the first divisor occurs when x is not prime.
I think you may obtain a better result inlining the primality() function inside the lpf5() function.
I've also tried to insert a table with some primes (from 1 to 383 - the primes in the first 128 results of the indicated formulas) inside the primality function, but the speed difference is unappreciable.
Here the code:
#include <stdio.h>
#include <math.h>
typedef long long unsigned int uint64;
uint64 lpf5(uint64 x);
uint64 primality(uint64 x);
uint64 lpf5(uint64 x)
{
uint64 x_=x;
while ( (x_=primality(x))!=x)
x=x/x_;
return x;
}
uint64 primality(uint64 x)
{
uint64 div=7,f=2,q;
if (x<4 || x==5)
return x;
if (!(x&1))
return 2;
if (!(x%3))
return 3;
if (!(x%5))
return 5;
q=sqrt(x);
while(div<=q) {
if (!(x%div)) {
return div;
}
f=6-f;
div+=f;
}
return x;
}
int main(void) {
uint64 x,k;
do {
printf("Input long int: ");
if (scanf("%llu",&x)<1)
break;
printf("Largest Prime Factor: %llu\n",lpf5(x));
} while(x!=0);
return 0;
}
I have implemented Sieve of Eratosthenes to solve the SPOJ problem PRIME1. Though the output is fine, my submission exceeds the time limit. How can I reduce the run time?
int main()
{
vector<int> prime_list;
prime_list.push_back(2);
vector<int>::iterator c;
bool flag=true;
unsigned int m,n;
for(int i=3; i<=32000;i+=2)
{
flag=true;
float s = sqrt(static_cast<float>(i));
for(c=prime_list.begin();c<=prime_list.end();c++)
{
if(*c>s)
break;
if(i%(*c)==0)
{
flag=false;
break;
}
}
if(flag==true)
{
prime_list.push_back(i);
}
}
int t;
cin>>t;
for (int times = 0; times < t; times++)
{
cin>> m >> n;
if (t) cout << endl;
if (m < 2)
m=2;
unsigned int j;
vector<unsigned int> req_list;
for(j=m;j<=n;j++)
{
req_list.push_back(j);
}
vector<unsigned int>::iterator k;
flag=true;
int p=0;
for(j=m;j<=n;j++)
{
flag=true;
float s = sqrt(static_cast<float>(j));
for(c=prime_list.begin();c<=prime_list.end();c++)
{
if((*c)!=j)
{
if((*c)>s)
break;
if(j%(*c)==0)
{
flag=false;
break;
}
}
}
if(flag==false)
{
req_list.erase (req_list.begin()+p);
p--;
}
p++;
}
for(k=req_list.begin();k<req_list.end();k++)
{
cout<<*k;
cout<<endl;
}
}
}
Your code is slow because you did not implement the Sieve of Eratosthenes algorithm. The algorithm works that way:
1) Create an array with size n-1, representing the numbers 2 to n, filling it with boolean values true (true means that the number is prime; do not forget we start counting from number 2 i.e. array[0] is the number 2)
2) Initialize array[0] = false.
3) Current_number = 2;
3) Iterate through the array by increasing the index by Current_number.
4) Search for the first number (except index 0) with true value.
5) Current_number = index + 2;
6) Continue steps 3-5 until search is finished.
This algorithm takes O(nloglogn) time.
What you do actually takes alot more time (O(n^2)).
Btw in the second step (where you search for prime numbers between n and m) you do not have to check if those numbers are prime again, ideally you will have calculated them in the first phase of the algorithm.
As I see in the site you linked the main problem is that you can't actually create an array with size n-1, because the maximum number n is 10^9, causing memory problems if you do it with this naive way. This problem is yours :)
I'd throw out what you have and start over with a really simple implementation of a sieve, and only add more complexity if really needed. Here's a possible starting point:
#include <vector>
#include <iostream>
int main() {
int number = 32000;
std::vector<bool> sieve(number,false);
sieve[0] = true; // Not used for now,
sieve[1] = true; // but you'll probably need these later.
for(int i = 2; i<number; i++) {
if(!sieve[i]) {
std::cout << "\t" << i;
for (int temp = 2*i; temp<number; temp += i)
sieve[temp] = true;
}
}
return 0;
}
For the given range (up to 32000), this runs in well under a second (with output directed to a file -- to the screen it'll generally be slower). It's up to you from there though...
I am not really sure that you have implemented the sieve of Erasthotenes. Anyway a couple of things that could speed up to some extent your algorithm would be: Avoid multiple rellocations of the vector contents by preallocating space (lookup std::vector<>::reserve). The operation sqrt is expensive, and you can probably avoid it altogether by modifying the tests (stop when the x*x > y instead of checking x < sqrt(y).
Then again, you will get a much better improvement by revising the actual algorithm. From a cursory look it seems as if you are iterating over all candidates and for each one of them, trying to divide with all the known primes that could be factors. The sieve of Erasthotenes takes a single prime and discards all multiples of that prime in a single pass.
Note that the sieve does not perform any operation to test whether a number is prime, if it was not discarded before then it is a prime. Each not prime number is visited only once for each unique factor. Your algorithm on the other hand is processing every number many times (against the existing primes)
I think one way to slightly speed up your sieve is the prevention of using the mod operator in this line.
if(i%(*c)==0)
Instead of the (relatively) expensive mod operation, maybe if you iterated forward in your sieve with addition.
Honestly, I don't know if this is correct. Your code is difficult to read without comments and with single letter variable names.
The way I understand the problem is that you have to generate all primes in a range [m,n].
A way to do this without having to compute all primes from [0,n], because this is most likely what's slowing you down, is to first generate all the primes in the range [0,sqrt(n)].
Then use the result to sieve in the range [m,n]. To generate the initial list of primes, implement a basic version of the sieve of Eratosthenes (Pretty much just a naive implementation from the pseudo code in the Wikipedia article will do the trick).
This should enable you to solve the problem in very little time.
Here's a simple sample implementation of the sieve of Eratosthenes:
std::vector<unsigned> sieve( unsigned n ) {
std::vector<bool> v( limit, true ); //Will be used for testing numbers
std::vector<unsigned> p; //Will hold the prime numbers
for( unsigned i = 2; i < n; ++i ) {
if( v[i] ) { //Found a prime number
p.push_back(i); //Stuff it into our list
for( unsigned j = i + i; j < n; j += i ) {
v[i] = false; //Isn't a prime/Is composite
}
}
}
return p;
}
It returns a vector containing only the primes from 0 to n. Then you can use this to implement the method I mentioned. Now, I won't provide the implementation for you, but, you basically have to do the same thing as in the sieve of Eratosthenes, but instead of using all integers [2,n], you just use the result you found. Not sure if this is giving away too much?
Since the SPOJ problem in the original question doesn't specify that it has to be solved with the Sieve of Eratosthenes, here's an alternative solution based on this article. On my six year old laptop it runs in about 15 ms for the worst single test case (n-m=100,000).
#include <set>
#include <iostream>
using namespace std;
int gcd(int a, int b) {
while (true) {
a = a % b;
if(a == 0)
return b;
b = b % a;
if(b == 0)
return a;
}
}
/**
* Here is Rowland's formula. We define a(1) = 7, and for n >= 2 we set
*
* a(n) = a(n-1) + gcd(n,a(n-1)).
*
* Here "gcd" means the greatest common divisor. So, for example, we find
* a(2) = a(1) + gcd(2,7) = 8. The prime generator is then a(n) - a(n-1),
* the so-called first differences of the original sequence.
*/
void find_primes(int start, int end, set<int>* primes) {
int an; // a(n)
int anm1 = 7; // a(n-1)
int diff;
for (int n = start; n < end; n++) {
an = anm1 + gcd(n, anm1);
diff = an - anm1;
if (diff > 1)
primes->insert(diff);
anm1 = an;
}
}
int main() {
const int end = 100000;
const int start = 2;
set<int> primes;
find_primes(start, end, &primes);
ticks = GetTickCount() - ticks;
cout << "Found " << primes.size() << " primes:" << endl;
set<int>::iterator iter = primes.begin();
for (; iter != primes.end(); ++iter)
cout << *iter << endl;
}
Profile your code, find hotspots, eliminate them. Windows, Linux profiler links.