hackerrank Ramanujan’s Prime Substrings 1 problem - c++

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.

Related

Trying out a problem but code I had written is not giving output for large numbers. why?

I was trying this question.
The prime factors of 13195 are 5, 7, 13 and 29.What is the largest prime factor of the number 600851475143 ?
And I had written the following code:
#include<iostream>
#define num 600851475143
using namespace std;
int isprime(unsigned long long int n)
{
unsigned long long int c=0;
for(unsigned long long int i=2;i<n;i++)
{
if(n%i==0)
{
c++;
break;
}
}
if(c==0)
{
return 1;
}
else
{
return 0;
}
}
int main()
{
unsigned long long int a,i,n=num;
while(n-- && n>1)
{
if(isprime(n)==1 && num%n==0)
{
cout<<n;
break;
}
}
return 0;
}
The problem occurring with the code is it is working for 13195 and other small values. But not getting any output for 600851475143. Can anyone explain why it is not working for large value and also tell the changes that should be made in these to get the correct output.
The below code snippets are from c (but should run quite nice with c++ as well):
#include <stdio.h>
#define uIntPrime unsigned long long int
#define uIntPrimeFormat "llu"
uIntPrime findSmallestPrimeFactor(uIntPrime num)
{
uIntPrime limit = num / 2 + 1;
for(uIntPrime i=2; i<limit; i++)
{
if((num % i) == 0)
{
return i;
}
}
return num;
}
uIntPrime findLargestPrimeFactor(uIntPrime num)
{
uIntPrime largestPrimeFactor = 1; // start with the smallest possible value
while (num > 1) {
uIntPrime primeFactor = findSmallestPrimeFactor(num);
if (primeFactor > largestPrimeFactor) largestPrimeFactor = primeFactor;
num = num / primeFactor;
}
return largestPrimeFactor;
}
How can this work?
(first function:) Counting the numbers up from 2 means you are starting with prime factors on the lower end. (Numbers that are non-prime when counting are just not working out as fraction-less divisors and at the same time their prime number factor components were already probed because they are lower.)
(second function:) If a valid factor is found then the factor is pulled out from the number in question. Thus the search for the now smallest prime in the pulled-out number can repeat. (The conditional might probably be superfluous due to lower numbers are found first anyway - but it might resemble a search pattern you are familiar with - like in a minimum/maximum/other-criteria search. I am now leaving it up to you to proof it right or wrong with testing with your own main routine.)
The stop condition is about having the last factor extracted means dividing the value by itself and getting a value of 1 for num.
(There is for sure still much space for speeding this up!)

How to print the b-th prime number coming after n?

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.

How to reduce the time in this program?

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.

How can I improve the efficiency of my solution for Prime Generator(SPOJ)? [duplicate]

This question already has answers here:
Sieve of Eratosthenes algorithm
(14 answers)
Closed 3 years ago.
The Prime Generator requires prime numbers between a certain range.
Input :
The input begins with the number t of test cases in a single line (t<=10). In each of the next t lines there are two numbers m and n
(1 <= m <= n <= 1000000000, n-m<=100000) separated by a space.
Output :
For every test case print all prime numbers p such that m <= p <= n, one number per line, test cases separated by an empty line.
My program runs perfectly with this solution but the time limit is exceeded and it isn't accepted as a solution.
I've replaced cin and cout with scanf and printf.
I've replaced for loops with while loops and what not. What other measures can I take to speed up my solution?
#include<iostream>
int prime(unsigned long int p)
{
int f=1,i=2;
while(i<=p/2)
{
if(p%i==0)
{ f=0;
break;
}
++i;
}
if(f==1)
{ printf("%d \n",p);
}
return 0;
}
int main()
{
int t, i=0;
unsigned long int m,n,j;
scanf("%d",&t);
while(i<t)
{
scanf("%lu%lu",&m,&n);
for(j=m;j<=n;++j)
{
if(j!=1&&j!=0)
prime(j);
}
printf("\n");
++i;
}
return 0;
}
Your code is inefficient because you’re using a slow algorithm to find primes. Changing a for loop to a while loop probably won’t speed up the code, but changing to a better algorithm will.
A faster algorithm:
There’s a really simple algorithm called the Sieve of Eratosthenes. We start out by making an array of bools. Mark all of them true. This array will let us keep track of which numbers are and aren’t prime. We’re gonna cross out the ones we know aren’t prime (by setting them to false).
Cross out 0 and 1 from the array
Starting with 4, cross out all numbers that are multiples of 2
Starting with 6, cross out all numbers that are multiples of 3
Starting with 10, cross out all multiples of 5
Starting with 14, cross out all multiples of 7
(Continue this process)
Example:
// takes a reference to a vector of bools
// a vector is a resizable array
void cross_out_multiples(std::vector<bool>& primes, int num) {
for(int i = num * 2; i < primes.size(); i += num) {
primes[i] = false;
}
}
std::vector<int> findPrimes(int max) {
std::vector<bool> primes(max); // create array with max elements
for(int i = 0; i < max; ++i) {
primes[i] = true;
}
// 0 and 1 aren’t prime, so we mark them false
primes[0] = false;
primes[1] = false;
// here we mark multiples of n false
for(int n = 2; n < max; n++) {
// if a number isn’t prime, we can skip it
if(not primes[n]) {
continue;
}
// if n squared is bigger than max, we already
// crossed out all multiples of n smaller than max
// so we don’t have any more work to do
if(n * n > max) {
break;
}
// now we just cross out multiples of n
cross_out_multiples(primes, n);
}
// now, take the numbers that are prime:
std::vector<int> listOfPrimes;
for(int i = 0; i < max; i++) {
// if a number is prime, add it to the list
if(primes[i]) {
listOfPrimes.push_back(i);
}
}
return listOfPrimes;
}I
Your code is correct, but (very) inefficient. The online judge not only requires correctness, but also efficiency.
The simple scanning algorithm of yours can be immediately made faster by two simple measures:
only test odd divisors
only test divisors up to sqrt(p) (which for large p is much smaller than p/2)
But ultimately learn about the sieve of Eratosthenes.

Project Euler 3 - Highest Prime Factor

before I start I want to clarify that I am not looking for code examples to get the answer; that would defeat the object of Project Euler.
The problem can be found here http://projecteuler.net/problem=3
I think I have a way of solving the problem, but the Algorithm is VERY slow; it has been running for nearly two and a half hours now. So I am looking for general advice on optimisation.
Thanks.
#include<iostream>
using namespace std;
bool primality(int);
int main(){
long long lim = 600851475143;
long long div = lim/2;
bool run = true;
while(run){
if(lim%div==0 && primality(div)){
cout << "HPF: " << div;
run = false;
}
else{
div--;
}
if(div<=1){
break;
}
}
return 0;
}
bool primality(int num){
for(int i=2; i<num; i++){
if(num%i==0 && i!=num){
return false;
}
else{
return true;
}
}
}
If you start div at 2 and count up instead of down, and divide it out from the number when the modulo is zero, you gain two big advantages that are useful here:
You don't have to check if div is prime, since it can't be composite because any prime factors smaller than it would already have been divided out.
You reduce the remaining problem size every time you find a factor, and, as it turns out, the input number has fairly small prime factors.
You could then also break once div*div is greater than the remaining number, as you know at that point that it must be a prime. This is because any divisors greater than the square root are "paired" with one less than the square root. However, since this is an "easy" problem, this optimization is not needed here (although it is useful for later problems).
# Possible solution but still its *time consuming* but answer can be guessed by the last option in console output
#include<stdio.h>
#include<string>
#include<iostream>
#include<math.h>
int prime(unsigned long long);
using namespace std;
int main(){
unsigned long long ii, ij; unsigned long long in;
cin>>in; ij = ceil(in/2);
if( (ij % 2) == 0 ) ij -= 1;
for(ii = 3 ;ii < ij;ii+= 2){
if(in % ii == 0){
if(prime(ii) == 1 ){
cout<<" ans "<<ii<<endl;
}
}
}
return 0;
}
int prime(unsigned long long ii){
unsigned long long ij;
for(ij = 3;ij < ii/2 ;ij += 2){
if( (ii % ij) ==0){
return 0;
}
}
return 1;
}