Generate Partition of integer into k different integers (C++) - c++

I have problem with the constraint
I have to partition it to "exact" k "different" integers
e.g. 10 = 1+2+7 -> valid
10 = 2+2+6 -> invalid
I don't want to print them, I want to store them in to vectors or something
I am thinking of recursive solution, but still can't come up with a efficient way to store them...(the solution I found can only print it)
And I think it should store in vector<vector>
the struct should be like this?
Partition(){
....
....
}
Partition_main(){
...
Partition()
....
}

In practice, the problem is to enumerate all the solutions.
This can be done by a DFS.
In the following code, the DFS is implemented with a help of a FIFO (i.e. a std::queue).
The little trick is, for a given candidate at a given step, to calculate the minimum
sum that can be obtained in the next steps.
If this minimum sum is larger than n, then we can stop the research in this direction.
#include <iostream>
#include <vector>
#include <queue>
#include <cassert>
struct Parti {
std::vector<int> v;
int sum = 0;
};
std::vector<std::vector<int>> get_partitions (int n, int k) {
std::vector<std::vector<int>> result;
std::queue<Parti> fifo;
Parti start;
fifo.push(start);
while (!fifo.empty()) {
Parti elt = fifo.front();
fifo.pop();
int sum = elt.sum;
int remain = k-elt.v.size();
if (remain == 1) {
int last = n - sum;
if (k > 1) assert (last > elt.v.back());
elt.v.push_back(last);
result.push_back (elt.v);
continue;
}
int i;
if (elt.v.size() == 0) i = 1;
else i = elt.v.back() + 1;
while (true) {
int min_sum = sum + remain*(2*i + remain - 1)/2;
if (min_sum > n) break;
Parti new_elt = elt;
new_elt.v.push_back(i);
new_elt.sum += i;
fifo.push (new_elt);
++i;
};
}
return result;
}
int main() {
int n = 15;
int k = 4;
auto res = get_partitions (n, k);
if (res.size() == 0) {
std::cout << "no partition possible\n";
return 0;
}
for (const auto& v: res) {
std::cout << n << " = ";
for (int i = 0; i < v.size(); ++i) {
std::cout << v[i];
if (i == v.size()-1) {
std::cout << "\n";
} else {
std::cout << " + ";
}
}
}
return 0;
}

Related

leetcode673:why did my solution run out of time?

Leetcode 673:
Given an integer array nums, return the number of longest increasing subsequences.
Notice that the sequence has to be strictly increasing.
And here is my code:
class Solution {
//recursively compute the max increasing subsequence length and number of them at a given start point
//and a Min which means the next value must be at least Min.The result will be recorded on dp and values in
//dp will be checked first
pair<int,int> length_and_count(int ptr,int Min,vector<int>& nums,vector<unordered_map<int,pair<int,int>>>& dp){
if(ptr==nums.size())
return make_pair(0,1);
if(dp[ptr].find(Min)!=dp[ptr].end()){
return dp[ptr][Min];
}
else{
if(nums[ptr]<Min)
return dp[ptr][Min]=length_and_count(ptr+1,Min,nums,dp);
else{
auto pair1=length_and_count(ptr+1,Min,nums,dp),pair2=length_and_count(ptr+1,nums[ptr]+1,nums,dp);
if(pair1.first>++pair2.first)
return dp[ptr][Min]=pair1;
else if(pair1.first<pair2.first)
return dp[ptr][Min]=pair2;
else return dp[ptr][Min]=make_pair(pair1.first,pair1.second+pair2.second);
}
}
}
public:
int findNumberOfLIS(vector<int>& nums) {
vector<unordered_map<int,pair<int,int>>> dp(nums.size());
return length_and_count(0,INT_MIN,nums,dp).second;
}
};
I think my solution is of complexity O(n2), because my dp parameters are the start point of nums and the current max value, which is got from the vector,so the size of dp can not be bigger than the square of the input vector.Since the problem size is less than 2000,my solution should be of 10s of ms.So whats's wrong with my solution?
Thanks for very interesting question! Was glad to implement my own solution for it, and to improve speed of yours.
On test of random input of 2000 elements I improved speed of your solution 8x-9x times. For that I did following things:
Interchanged order of vector and unordered_map, by making dp structure unordered_map<int, shared_ptr<vector<pair<int, int>>>>. This way we can later reuse pointer to Min entry of unordered map, by passing this entry downwards to recursive function.
In dp wrapped vector into std::shared_ptr. This allows to be sure that vector will not change memory location even if unordered map grows.
Instead of doing same unordered map search again with dp[ptr][Min] I did search just once inside single call of function through .find(Min) and reused this iterator later in all other places of a function.
Passed Min_vec pointer down to all recursive calls, so that other function calls don't search inside unordered map again for same Min entry. Just single place was not reusing this pointer, where nums[ptr] + 1 was passed as Min.
Created special lambda function GetMinVec() which finds and returns pointer to Min entry. In case if this entry didn't exist yet I initialize it by allocating shared_ptr and resizing vector to size of nums.size() filled with pair(-1, -1) which signifies empty value.
All steps above boosted your solution by 8x-9x times. Your original solution is located in my code as SolutionOriginal class. While my boosted variant is SolutionBoosted.
Also I created my own solution that is 100x faster than your original and 11x-12x faster than boosted original. This new solution I called SolutionSqrt. It works as follows:
Lets create K = sqrt(N) buckets. Each of K buckets will have around K elements on average at the end.
Each bucket will help us to narrow search of all elements that are smaller than current one. For each new number we will find the bucket index buck_i that says that all buckets with smaller index contain elements not bigger than current.
Inside current bucket buck_i we will do linear search to find all elements that are smaller than current.
Each bucket contains a Heap array that grows by using std::push_heap. This Heap is sorted in such a way that its first element (head) contains largest element.
Bucket's Heap is sorted in such a way that first element has longest chain of numbers located in this heap.
We do Sqrt(N) + Sqrt(N) searches on average for each new number. And we search how can we extend current longest chain by adding this new element.
If longest chain is succeded to be prolonged then we remember new maximal length and new maximal count of current bucket buck_i. Also then new element becomes first Heap element as providing the longest chain.
Each bucket has its own length of longest chain and count of such chains formed.
Overall complexity of such algorithm is O(N * Sqrt(N)). This complexity can be improved even further if instead of 2-level buckets we make 3-level buckets in this case we will achieve complexity O(N * N^(1/3)). This O(N * Sqrt(N)) complexity is much less than original OP's code that is O(N^2).
I did timings of all 3 variants of solutions on random test set of 2000 numbers. Timings can be seen after the code.
Try it online!
#include <cstdint>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <limits>
class SolutionSqrt {
public:
using u64 = uint64_t;
using NumT = int;
u64 findNumberOfLIS(std::vector<NumT> const & nums) {
size_t const
N = nums.size(),
nbucks = std::max<size_t>(1, std::llround(std::sqrt(N))),
buck_size = (N + nbucks - 1) / nbucks;
std::vector<size_t> si(N), rsi(N), ll(N);
std::vector<u64> lc(N);
for (size_t i = 0; i < si.size(); ++i)
si[i] = i;
std::sort(si.begin(), si.end(), [&](size_t a, size_t b){
return nums[a] < nums[b];
});
for (size_t i = 0; i < rsi.size(); ++i)
rsi[si[i]] = i;
struct Buck {
std::vector<size_t> sj;
size_t max_ll = 0;
u64 max_lc = 0;
NumT max_num = std::numeric_limits<NumT>::min(),
min_num = std::numeric_limits<NumT>::max();
};
std::vector<Buck> bucks(nbucks);
for (size_t i = 0; i < N; ++i) {
auto const num = nums[i];
size_t const buck_i = rsi[i] / buck_size;
size_t max_ll = 0;
for (size_t j = 0; j <= buck_i; ++j) {
auto const & buckj = bucks[j];
if (buckj.sj.empty())
continue;
if (j < buck_i && buckj.max_num < num)
max_ll = std::max(max_ll, buckj.max_ll);
else {
if (buckj.min_num == buckj.max_num && buckj.max_num == num)
continue;
for (size_t k = 0; k < buckj.sj.size(); ++k)
if (nums[buckj.sj[k]] < num)
max_ll = std::max(max_ll, ll[buckj.sj[k]]);
}
}
if (max_ll > 0) {
u64 clc = 0;
for (size_t j = 0; j <= buck_i; ++j) {
auto const & buckj = bucks[j];
if (buckj.sj.empty())
continue;
if (j < buck_i && buckj.max_num < num) {
if (ll[buckj.sj[0]] == max_ll)
clc += buckj.max_lc;
} else {
if (buckj.min_num == buckj.max_num && buckj.max_num == num)
continue;
for (size_t k = 0; k < buckj.sj.size(); ++k)
if (nums[buckj.sj[k]] < num && ll[buckj.sj[k]] == max_ll)
clc += lc[buckj.sj[k]];
}
}
ll[i] = max_ll + 1;
lc[i] = clc;
} else {
ll[i] = 1;
lc[i] = 1;
}
auto & buck = bucks[buck_i];
bool const new_max = buck.sj.empty() || ll[i] > ll[buck.sj[0]];
buck.sj.push_back(i);
std::push_heap(buck.sj.begin(), buck.sj.end(), [&](size_t a, size_t b){
return ll[a] < ll[b];
});
if (ll[i] >= buck.max_ll)
buck.max_lc = lc[i] + (new_max ? u64(0) : buck.max_lc);
buck.max_ll = std::max(buck.max_ll, ll[i]);
buck.min_num = std::min(buck.min_num, num);
buck.max_num = std::max(buck.max_num, num);
}
size_t total_max_ll = 0;
for (size_t i = 0; i < bucks.size(); ++i)
if (!bucks[i].sj.empty())
total_max_ll = std::max(total_max_ll, bucks[i].max_ll);
u64 total_lc = 0;
for (size_t i = 0; i < bucks.size(); ++i)
if (!bucks[i].sj.empty() && ll[bucks[i].sj[0]] == total_max_ll)
total_lc += bucks[i].max_lc;
//std::cout << "Length " << total_max_ll << std::endl;
//std::cout << "Count " << total_lc << std::endl;
return total_lc;
}
};
#include <unordered_map>
#include <climits>
#include <memory>
using namespace std;
class SolutionOriginal {
// recursively compute the max increasing subsequence length and number of them at a given start point
// and a Min which means the next value must be at least Min.The result will be recorded on dp and values in
// dp will be checked first
pair<int, int> length_and_count(int ptr, int Min, vector<int> & nums,
vector<unordered_map<int, pair<int, int>>> & dp) {
if (ptr == nums.size())
return make_pair(0, 1);
if (dp[ptr].find(Min) != dp[ptr].end()) {
return dp[ptr][Min];
} else {
if (nums[ptr] < Min)
return dp[ptr][Min] = length_and_count(ptr + 1, Min, nums, dp);
else {
auto pair1 = length_and_count(ptr + 1, Min, nums, dp),
pair2 = length_and_count(ptr + 1, nums[ptr] + 1, nums, dp);
if (pair1.first > ++pair2.first)
return dp[ptr][Min] = pair1;
else if (pair1.first < pair2.first)
return dp[ptr][Min] = pair2;
else
return dp[ptr][Min] = make_pair(pair1.first, pair1.second + pair2.second);
}
}
}
public:
int findNumberOfLIS(vector<int> nums) {
vector<unordered_map<int, pair<int, int>>> dp(nums.size());
auto p = length_and_count(0, INT_MIN, nums, dp);
// std::cout << "Length " << p.first << std::endl;
// std::cout << "Count " << p.second << std::endl;
return p.second;
}
};
class SolutionBoosted {
// recursively compute the max increasing subsequence length and number of them at a given start point
// and a Min which means the next value must be at least Min.The result will be recorded on dp and values in
// dp will be checked first
pair<int, int> length_and_count(int ptr, int Min, vector<int> & nums,
unordered_map<int, shared_ptr<vector<pair<int, int>>>> & dp,
vector<pair<int, int>> * Min_vec = nullptr) {
if (ptr == nums.size())
return make_pair(0, 1);
auto GetMinVec = [&]{
auto it0 = dp.find(Min);
if (it0 != dp.end())
return it0->second.get();
auto it1 = dp.insert(make_pair(Min, make_shared<
vector<pair<int, int>>>())).first;
it1->second->resize(nums.size(), make_pair(-1, -1));
return it1->second.get();
};
if (!Min_vec)
Min_vec = GetMinVec();
auto & e = (*Min_vec)[ptr];
if (e.first != -1)
return e;
else {
if (nums[ptr] < Min)
return e = length_and_count(ptr + 1, Min, nums, dp, Min_vec);
else {
auto pair1 = length_and_count(ptr + 1, Min, nums, dp, Min_vec),
pair2 = length_and_count(ptr + 1, nums[ptr] + 1, nums, dp);
if (pair1.first > ++pair2.first)
return e = pair1;
else if (pair1.first < pair2.first)
return e = pair2;
else
return e = make_pair(
pair1.first, pair1.second + pair2.second);
}
}
}
public:
int findNumberOfLIS(vector<int> nums) {
unordered_map<int, shared_ptr<vector<pair<int, int>>>> dp;
auto p = length_and_count(0, INT_MIN, nums, dp);
// std::cout << "Length " << p.first << std::endl;
// std::cout << "Count " << p.second << std::endl;
return p.second;
}
};
#include <random>
#include <chrono>
int main() {
std::mt19937_64 rng(123);
std::uniform_int_distribution<int> distr(-100, 100);
std::vector<int> v;
for (size_t i = 0; i < (1 << 11); ++i)
v.push_back(distr(rng));
{
auto tb = std::chrono::system_clock::now();
std::cout << "Sqrt " << SolutionSqrt().findNumberOfLIS(v) << " ";
std::cout << "Time " << std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now() - tb).count() / 1000000.0 << " sec" << std::endl;
}
{
auto tb = std::chrono::system_clock::now();
std::cout << "Original "
<< SolutionOriginal().findNumberOfLIS(v) << " ";
std::cout << "Time " << std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now() - tb).count() / 1000000.0 << " sec" << std::endl;
}
{
auto tb = std::chrono::system_clock::now();
std::cout << "Original_Boosted "
<< SolutionBoosted().findNumberOfLIS(v) << " ";
std::cout << "Time " << std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now() - tb).count() / 1000000.0 << " sec" << std::endl;
}
}
Output:
Sqrt 15240960 Time 0.000856 sec
Original 15240960 Time 0.081954 sec
Original_Boosted 15240960 Time 0.011343 sec

Breaking out of loop from function after printing the last prime number of a given range

I'm writing a code to find the last prime number of a given range. Suppose the range is 1 to 50. Then the last prime no. I want to print must be 47. My idea was to maybe reverse the order of prime numbers in the range and then try printing only the first value. Again kinda like if my order was 1 to 50 then I would start printing from 47, 43 and so on and only print 47. But I'm stuck and not getting ideas on how I could do this. here's my code
int prime_bef(int n)
{
int check = 0;
for (int i = 1; i <= n; i++)
{
if (n % i == 0)
{
check++;
}
}
if (check == 2)
{
cout << n << " ";
}
return 0;
}
int main ()
{
int l;
int u;
cin >> l >> u;
for (int i = u; i >= l; i--)
{
prime_bef(i);
}
return 0;
}
You can just use exit() in the place you want to end the program, and it works fine in your case. But by far the best approach is returning a value to test for continuation, it is the most readable.
#include<iostream>
#include <stdlib.h>
using namespace std;
int prime_bef(int n)
{
int check = 0;
for (int i = 1; i <= n; i++)
{
if (n % i == 0)
{
check++;
}
}
if (check == 2)
{
cout << n << " ";
exit(0);
}
return 0;
}
int main ()
{
int l;
int u;
cin >> l >> u;
for (int i = u; i >= l; i--)
{
prime_bef(i);
}
return 0;
}
Same code using bool return type:
#include<iostream>
using namespace std;
bool prime_bef(int n)
{
int check = 0;
for (int i = 1; i <= n; i++)
{
if (n % i == 0)
{
check++;
}
}
if (check == 2)
{
cout << n << " ";
return true;
}
return false;
}
int main ()
{
int l;
int u;
cin >> l >> u;
for (int i = u; i >= l; i--)
{
if(prime_bef(i))
break;
}
return 0;
}
Here is a simple and efficient way to check if the number is prime. I am checking if the number is prime and when it is true I am printing the number and breaking the loop so that only 1 number is printed. You can always remove the break statement and print all prime numbers in range.
#include<iostream>
using namespace std;
bool isPrime(int n){
if(n==2)return true;
if(n%2==0 || n==1)return false;
for(int i=3; i*i<=n; ++i){
if(n%i==0){
return false;
}
}
return true;
}
int main (){
int l, u;
cin>>l>>u;
for (int i = u; i >= l; i--){
if(isPrime(i)){
cout<<i<<"\n";
break;
}
}
return 0;
}
I'll give you a hint... while you are iteratively checking for the prime nature of the number, also check whether the last prime number calculated in the loop is greater than the max term of the range and break the loop when the condition becomes false.
Here a C++17 approach :
#include <cmath>
#include <iostream>
#include <vector>
// type to use for storing primes
using prime_t = unsigned long;
// there is a way to determine an upper bound to the number of primes smaller then a maximum number.
// See : https://primes.utm.edu/howmany.html
// this can be used to estimate the size of the output buffer (vector)
prime_t pi_n(const prime_t max)
{
prime_t pi_n{ max };
if (max > 10)
{
auto ln_n = std::log(static_cast<double>(max));
auto value = static_cast<double>(max) / (ln_n - 1.0);
pi_n = static_cast<prime_t>(value + 0.5);
}
return pi_n;
}
// Calculate prime numbers smaller then max
// https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
auto calculate_primes(const prime_t max)
{
std::vector<bool> is_primes(max, true);
// 0, 1 are not primes
is_primes[0] = false;
is_primes[1] = false;
// sieve
for (prime_t n = prime_t{ 2 }; n < prime_t{ max }; ++n)
{
if (is_primes[n])
{
auto n2 = n * n;
for (prime_t m = n2; m < max; m += n)
{
is_primes[m] = false;
}
}
}
// avoid unnecessary resizes of vector by pre-allocating enough entries to hold result
prime_t n{ 0 };
std::vector<prime_t> primes;
primes.reserve(pi_n(max));
// add all prime numbers found by the sieve
for (const auto is_prime : is_primes)
{
if (is_prime) primes.push_back(n);
n++;
}
return primes;
}
int main()
{
const prime_t max{ 50 };
auto primes = calculate_primes(max);
// max prime is last one in container
auto max_prime = primes.back();
std::cout << "maximum prime number smaller then " << max << ", is " << max_prime << std::endl;
}

Why is my "vector subscript out of range"?

I am trying to make an algorithm that checks for duplicates. The algorithm takes in an integer p and aims to find the primitive root g if it satisfies that all values of g^x mod p (for values of x in the range of 0 to p - 2) are different.
I basically try to store all the values of g^x mod p in a vector and then I check for duplicates using a digitsTable vector that counts the frequency of each individual number. If the number is greater than 1, then it means there's a duplicate.
But the thing is, halfway through the algorithm, an error appears saying that the vector subscript is out of range. I did a bit of research and it refers to an accessing violation. I don't see where this is going wrong.
Here's the code:
#include <iostream>
#include <vector>
#define ll long long int
using namespace std;
ll gcd(ll a, ll b) {
ll r;
while (b != 0) {
r = a % b;
a = b;
b = r;
}
return a;
}
int main()
{
ll p;
cin >> p;
vector<ll> distinctIntegers;
vector<ll> digitsTable;
bool searching = true;
ll g = 2;
ll smallestRoot;
ll rootCount = 1;
while (searching) {
bool primeRoot = true;
distinctIntegers.push_back(1);
for (ll x = 1; x <= p - 2; ++x) {
distinctIntegers.push_back(g * distinctIntegers[x - 1] % p);
}
// fills a vector with zeroes
for (ll i = 0; i < distinctIntegers.size(); ++i) {
digitsTable.push_back(0);
}
// counts the frequency of each element in distinctIntegers.size()
for (ll i = 0; i < distinctIntegers.size(); ++i) {
++digitsTable[distinctIntegers[i]];
}
for (ll i = 0; i < distinctIntegers.size(); ++i) {
if (digitsTable[i] > 1) {
primeRoot = false;
++g;
break;
}
}
if (primeRoot) {
smallestRoot = g;
searching = false;
}
//test
distinctIntegers.clear();
digitsTable.clear();
}
for (int m = smallestRoot; m <= p - 1; ++m) {
if (gcd(m, p - 1) == 1) {
rootCount++;
}
}
cout << smallestRoot << " " << rootCount;
return 0;
// USED FOR TESTING
/*
* for (int i = 0; i < digitsTable.size(); ++i) {
cout << digitsTable[i] << " ";
}
cout << endl;
*/
}

Print prime factorization in exponential form in C++

So far I have this code. I'm trying to print prime factorization with exponents. For example, if my input is 20, the output should be 2^2, 5
#include <iostream>
#include <cmath>
using namespace std;
void get_divisors (int n);
bool prime( int n);
int main(int argc, char** argv) {
int n = 0 ;
cout << "Enter a number and press Enter: ";
cin >>n;
cout << " Number n is " << n << endl;
get_divisors(n);
cout << endl;
return 0;
}
void get_divisors(int n){
double sqrt_of_n = sqrt(n);
for (int i =2; i <= sqrt_of_n; ++i){
if (prime (i)){
if (n % i == 0){
cout << i << ", ";
get_divisors(n / i);
return;
}
}
}
cout << n;
}
bool prime (int n){
double sqrt_of_n = sqrt (n);
for (int i = 2; i <= sqrt_of_n; ++i){
if ( n % i == 0) return 0;
}
return 1;
}
I hope someone can help me with this.
You can use an std::unordered_map<int, int> to store two numbers (x and n for x^n). Basically, factorize the number normally by looping through prime numbers smaller than the number itself, dividing the number by the each prime as many times as possible, and recording each prime you divide by. Each time you divide by a prime number p, increment the counter at map[p].
I've put together a sample implementation, from some old code I had. It asks for a number and factorizes it, displaying everything in x^n.
#include <iostream>
#include <unordered_map>
#include <cmath>
bool isPrime(const int& x) {
if (x < 3 || x % 2 == 0) {
return x == 2;
} else {
for (int i = 3; i < (int) (std::pow(x, 0.5) + 2); i += 2) {
if (x % i == 0) {
return false;
}
}
return true;
}
}
std::unordered_map<int, int> prime_factorize(const int &x) {
int currentX = abs(x);
if (isPrime(currentX) || currentX < 4) {
return {{currentX, 1}};
}
std::unordered_map<int, int> primeFactors = {};
while (currentX % 2 == 0) {
if (primeFactors.find(2) != primeFactors.end()) {
primeFactors[2]++;
} else {
primeFactors[2] = 1;
}
currentX /= 2;
}
for (int i = 3; i <= currentX; i += 2) {
if (isPrime(i)) {
while (currentX % i == 0) {
if (primeFactors.find(i) != primeFactors.end()) {
primeFactors[i]++;
} else {
primeFactors[i] = 1;
}
currentX /= i;
}
}
}
return primeFactors;
}
int main() {
int x;
std::cout << "Enter a number: ";
std::cin >> x;
auto factors = prime_factorize(x);
std::cout << x << " = ";
for (auto p : factors) {
std::cout << "(" << p.first << " ^ " << p.second << ")";
}
}
Sample output:
Enter a number: 1238
1238 = (619 ^ 1)(2 ^ 1)
To begin with, avoid using namespace std at the top of your program. Second, don't use function declarations when you can put your definitions before the use of those functions (but this may be a matter of preference).
When finding primes, I'd divide the number by 2, then by 3, and so on. I can also try with 4, but I'll never be able to divide by 4 if 2 was a divisor, so non primes are automatically skipped.
This is a possible solution:
#include <iostream>
int main(void)
{
int n = 3 * 5 * 5 * 262417;
bool first = true;
int i = 2;
int count = 0;
while (i > 1) {
if (n % i == 0) {
n /= i;
++count;
}
else {
if (count > 0) {
if (!first)
std::cout << ", ";
std::cout << i;
if (count > 1)
std::cout << "^" << count;
first = false;
count = 0;
}
i++;
if (i * i > n)
i = n;
}
}
std::cout << "\n";
return 0;
}
Note the i * i > n which is an alternative to the sqrt() you are using.

Iterative equivalent a recursive algorithm

I'm trying to modify this program to their equivalent iterative but it becomes very difficult to me because as yet i'm still a newbie, it comes to an algorithm that decomposes a number into its prime factors, here the code:
#include <iostream>
#include <map>
#include <cmath>
std::map< int, std::pair<int, int> > decompositions;
void descompon_number(int num, int root, int i = 2 )
{
auto iterator = decompositions.find(num);
if (iterator == decompositions.end())
{
if (num > 1 && i <= root)
{
if (num % i == 0)
{
int n = num / i;
decompositions[num] = std::make_pair(i, n);
descompon_number(n, (int) std::sqrt(n));
}
else
descompon_number(num, root, i + 1);
}
else
decompositions[num] = std::make_pair(num, 1);
}
}
void show(int num, int factor, int exponent, int see)
{
auto pair = decompositions[num];
if (num <= 1 || factor != pair.first)
{
if (see)
std::cout << factor;
if (exponent > 1 && see)
std::cout << "^" << exponent;
if (pair.first > 1 && see)
std::cout << " * ";
exponent = 0;
}
if (num > 1)
show(pair.second, pair.first, exponent + 1, see);
}
void descompon(int a, int b, int see)
{
if (a <= b)
{
descompon_number(a, (int) std::sqrt(a));
if (see)
std::cout << a << " = ";
show(a, decompositions[a].first, 0, see);
if (see)
std::cout << std::endl;
descompon(a + 1, b, see);
}
}
int main()
{
descompon(2, 100, 1);
return 0;
}
Someone can help me out with this
Finding prime factors iteratively is not very complicated.
Here's the pseudocode how to do this.
Let P be a list of the first n prime numbers, such that Pn <= sqrt(m).
array findPrimeFactors(m)
answer = new array
for p in P
while m can be divided by p
m = m / p
answer.append(p)
if m == 1
break
return answer
Note: empty array is returned if m is prime.
You can use an erastotenes' sieve to compute prime numbers, and later you can use the algorithm posted by popovitsj.
The following code can be optimized, but its main purpose is to show you how to proceed.
Complete example:
#include <iostream>
#include <vector>
using namespace std;
// Returns a vector containing the first <number> prime numbers
vector<int> erastotenes_sieve(int number)
{
vector<int> result;
int *sieve = new int[number];
for (int i = 0; i < number; i++) sieve[i] = 0;
// Traverse the sieve marking multiples.
for (int i = 2; i < number / 2; i++)
for (int j = i + i; j < number; j += i)
sieve[j] = 1;
// Collect unaffected indexes, those are prime numbers.
for (int i = 2; i < number; i++)
if (!sieve[i])
result.push_back(i);
delete [] sieve;
return result;
}
vector<int> descompon_number(int number)
{
vector<int> result;
if (number == 1 || number == 0)
{
result.push_back(number);
return result;
}
for (int &prime : erastotenes_sieve(number))
{
while (number % prime == 0 && number != 1)
{
number /= prime;
result.push_back(prime);
}
}
return result;
}
int main()
{
for (auto &i : descompon_number(20))
{
cout << i << endl;
}
return 0;
}