A vector as a patchwork of two other vectors - c++

Subset a vector
Below is the benchmark of two different solutions to subset a vector
#include <vector>
#include <iostream>
#include <iomanip>
#include <sys/time.h>
using namespace std;
int main()
{
struct timeval timeStart,
timeEnd;
// Build the vector 'whole' to subset
vector<int> whole;
for (int i = 0 ; i < 10000000 ; i++)
    {
whole.push_back(i);
}
// Solution 1 - Use a for loops
gettimeofday(&timeStart, NULL);
vector<int> subset1;
subset1.reserve(9123000 - 1200);
for (int i = 1200 ; i < 9123000 ; i++)
{
subset1.push_back(i);
}
gettimeofday(&timeEnd, NULL);
cout << "Solution 1 took " << ((timeEnd.tv_sec - timeStart.tv_sec) * 1000000 + timeEnd.tv_usec - timeStart.tv_usec) << " us" << endl;
// Solution 2 - Use iterators and constructor
gettimeofday(&timeStart, NULL);
vector<int>::iterator first = whole.begin() + 1200;
vector<int>::iterator last = whole.begin() + 9123000;
vector<int> subset2(first, last);
gettimeofday(&timeEnd, NULL);
cout << "Solution 2 took " << ((timeEnd.tv_sec - timeStart.tv_sec) * 1000000 + timeEnd.tv_usec - timeStart.tv_usec) << " us" << endl;
}
On my old laptop, it outputs
Solution 1 took 243564 us
Solution 2 took 164220 us
Clearly solution 2 is faster.
Make a patchwork of two vectors
I would like to create a vector as a patchwork of two different vectors of the same size. The vector starts as one and then takes the value of the other and back and forth. I guess I don't fully understand how to copy values to a vector by using iterator pointing to elements in another vector. The only implementation I can think of requires using an analogous to solution 1 above. Something like...
#include <vector>
#include <iostream>
#include <cmath>
#include <iomanip>
#include <sys/time.h>
#include <limits.h>
using namespace std;
int main()
{
// input
vector<int> breakpoints = {2, 5, 7, INT_MAX};
vector<int> v1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
vector<int> v2 = { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
// Create output
vector<int> ExpectedOutput;
ExpectedOutput.reserve(v1.size());
int origin = 0;
int breakpoints_index = 0;
for (int i = 0 ; i < v1.size() ; i++)
{
if (origin)
{
ExpectedOutput.push_back(v1[i]);
} else
{
ExpectedOutput.push_back(v2[i]);
}
if (breakpoints[breakpoints_index] == i)
{
origin = !origin;
breakpoints_index++;
}
}
// print output
cout << "output: ";
for (int i = 0 ; i < ExpectedOutput.size() ; i++)
{
cout << ExpectedOutput[i] << " ";
}
cout << endl;
return 0;
}
which outputs
output: 10 20 30 4 5 6 70 80 9
It feels like there must be a better solution such as something analogous to Solution 2 from above. Is there a faster solution?

Repeating push_back() means that every time around the loop, a check is being performed to ensure capacity() is large enough (if not, then more space must be reserved). When you copy a whole range, only one capacity() check needs to be done.
You can still be a bit smarter with your interleaving by copying chunks. Here's the very basic idea:
int from = 0;
for( int b : breakpoints )
{
std::swap( v1, v2 );
int to = 1 + std::min( b, static_cast<int>( v1.size() ) - 1 );
ExpectedOutput.insert( ExpectedOutput.end(), v1.begin() + from, v1.begin() + to );
from = to;
}
For the sake of brevity, this code actually swaps v1 and v2 and so always operates on v1. I did the swap before the insert, to emulate the logic in your code (which is acting on v2 first). You can do this in a non-modifying way instead if you want.
Of course, you can see a bit more is going on in this code. It would only make sense if you have considerably fewer breakpoints than values. Note that it also assumes v1 and v2 are the same length.

Related

Divide elements of a sorted array into least number of groups such that difference between the elements of the new array is less than or equal to 1

How to divide elements in an array into a minimum number of arrays such that the difference between the values of elements of each of the formed arrays does not differ by more than 1?
Let's say that we have an array: [4, 6, 8, 9, 10, 11, 14, 16, 17].
The array elements are sorted.
I want to divide the elements of the array into a minimum number of array(s) such that each of the elements in the resulting arrays do not differ by more than 1.
In this case, the groupings would be: [4], [6], [8, 9, 10, 11], [14], [16, 17]. So there would be a total of 5 groups.
How can I write a program for the same? Or you can suggest algorithms as well.
I tried the naive approach:
Obtain the difference between consecutive elements of the array and if the difference is less than (or equal to) 1, I add those elements to a new vector. However this method is very unoptimized and straight up fails to show any results for a large number of inputs.
Actual code implementation:
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
int main() {
int num = 0, buff = 0, min_groups = 1; // min_groups should start from 1 to take into account the grouping of the starting array element(s)
cout << "Enter the number of elements in the array: " << endl;
cin >> num;
vector<int> ungrouped;
cout << "Please enter the elements of the array: " << endl;
for (int i = 0; i < num; i++)
{
cin >> buff;
ungrouped.push_back(buff);
}
for (int i = 1; i < ungrouped.size(); i++)
{
if ((ungrouped[i] - ungrouped[i - 1]) > 1)
{
min_groups++;
}
}
cout << "The elements of entered vector can be split into " << min_groups << " groups." << endl;
return 0;
}
Inspired by Faruk's answer, if the values are constrained to be distinct integers, there is a possibly sublinear method.
Indeed, if the difference between two values equals the difference between their indexes, they are guaranteed to belong to the same group and there is no need to look at the intermediate values.
You have to organize a recursive traversal of the array, in preorder. Before subdividing a subarray, you compare the difference of indexes of the first and last element to the difference of values, and only subdivide in case of a mismatch. As you work in preorder, this will allow you to emit pieces of the groups in consecutive order, as well as detect to the gaps. Some care has to be taken to merge the pieces of the groups.
The worst case will remain linear, because the recursive traversal can degenerate to a linear traversal (but not worse than that). The best case can be better. In particular, if the array holds a single group, it will be found in time O(1). If I am right, for every group of length between 2^n and 2^(n+1), you will spare at least 2^(n-1) tests. (In fact, it should be possible to estimate an output-sensitive complexity, equal to the array length minus a fraction of the lengths of all groups, or similar.)
Alternatively, you can work in a non-recursive way, by means of exponential search: from the beginning of a group, you start with a unit step and double the step every time, until you detect a gap (difference in values too large); then you restart with a unit step. Here again, for large groups you will skip a significant number of elements. Anyway, the best case can only be O(Log(N)).
I would suggest encoding subsets into an offset array defined as follows:
Elements for set #i are defined for indices j such that offset[i] <= j < offset[i+1]
The number of subsets is offset.size() - 1
This only requires one memory allocation.
Here is a complete implementation:
#include <cassert>
#include <iostream>
#include <vector>
std::vector<std::size_t> split(const std::vector<int>& to_split, const int max_dist = 1)
{
const std::size_t to_split_size = to_split.size();
std::vector<std::size_t> offset(to_split_size + 1);
offset[0] = 0;
size_t offset_idx = 1;
for (std::size_t i = 1; i < to_split_size; i++)
{
const int dist = to_split[i] - to_split[i - 1];
assert(dist >= 0); // we assumed sorted input
if (dist > max_dist)
{
offset[offset_idx] = i;
++offset_idx;
}
}
offset[offset_idx] = to_split_size;
offset.resize(offset_idx + 1);
return offset;
}
void print_partition(const std::vector<int>& to_split, const std::vector<std::size_t>& offset)
{
const std::size_t offset_size = offset.size();
std::cout << "\nwe found " << offset_size-1 << " sets";
for (std::size_t i = 0; i + 1 < offset_size; i++)
{
std::cout << "\n";
for (std::size_t j = offset[i]; j < offset[i + 1]; j++)
{
std::cout << to_split[j] << " ";
}
}
}
int main()
{
std::vector<int> to_split{4, 6, 8, 9, 10, 11, 14, 16, 17};
std::vector<std::size_t> offset = split(to_split);
print_partition(to_split, offset);
}
which prints:
we found 5 sets
4
6
8 9 10 11
14
16 17
Iterate through the array. Whenever the difference between 2 consecutive element is greater than 1, add 1 to your answer variable.
`
int getPartitionNumber(int arr[]) {
//let n be the size of the array;
int result = 1;
for(int i=1; i<n; i++) {
if(arr[i]-arr[i-1] > 1) result++;
}
return result;
}
`
And because it is always nice to see more ideas and select the one that suites you best, here the straight forward 6 line solution. Yes, it is also O(n). But I am not sure, if the overhead for other methods makes it faster.
Please see:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
using Data = std::vector<int>;
using Partition = std::vector<Data>;
Data testData{ 4, 6, 8, 9, 10, 11, 14, 16, 17 };
int main(void)
{
// This is the resulting vector of vectors with the partitions
std::vector<std::vector<int>> partition{};
// Iterating over source values
for (Data::iterator i = testData.begin(); i != testData.end(); ++i) {
// Check,if we need to add a new partition
// Either, at the beginning or if diff > 1
// No underflow, becuase of boolean shortcut evaluation
if ((i == testData.begin()) || ((*i) - (*(i-1)) > 1)) {
// Create a new partition
partition.emplace_back(Data());
}
// And, store the value in the current partition
partition.back().push_back(*i);
}
// Debug output: Copy all data to std::cout
std::for_each(partition.begin(), partition.end(), [](const Data& d) {std::copy(d.begin(), d.end(), std::ostream_iterator<int>(std::cout, " ")); std::cout << '\n'; });
return 0;
}
Maybe this could be a solution . . .
How do you say your approach is not optimized? If your is correct, then according to your approach, it takes O(n) time complexity.
But you can use binary-search here which can optimize in average case. But in worst case this binary search can take more than O(n) time complexity.
Here's a tips,
As the array sorted so you will pick such a position whose difference is at most 1.
Binary search can do this in simple way.
int arr[] = [4, 6, 8, 9, 10, 11, 14, 16, 17];
int st = 0, ed = n-1; // n = size of the array.
int partitions = 0;
while(st <= ed) {
int low = st, high = n-1;
int pos = low;
while(low <= high) {
int mid = (low + high)/2;
if((arr[mid] - arr[st]) <= 1) {
pos = mid;
low = mid + 1;
} else {
high = mid - 1;
}
}
partitions++;
st = pos + 1;
}
cout<< partitions <<endl;
In average case, it is better than O(n). But in worst case (where the answer would be equal to n) it takes O(nlog(n)) time.

Strange bug in a while loop (C++)

I'm trying to make a program that works with a simple algorithm.
But for some reason, I get a strange bug (below is the simplified version of the program).
#include "stdafx.h"
#include <iostream>
#include <string>
using std::cout;
using std::string;
void find(int arr[], string name)
{
int t = 8;
int i = 0;
int v = 0;
// t should become equal to the smallest int of the array after this.
while (arr[i])
{
if (arr[i] < t)
{
t = arr[i];
}
++i;
}
/* When this statement below gets executed t gets what looks like a
random value for some reason */
cout << arr[t] << '\n';
for (int b = 0; b < 2; ++b)
{
if (t == arr[b])
{
v = b;
}
}
/* Again, arr[v] gets what looks like a random number */
cout << "The cheapest " << name << " is number " << arr[v] << ".";
}
int main()
{
/* [0] = "Cost for Steve"
[1] = "Cost for Mark"
[2] = "Cost for Andrew" */
int cleaning[] = { 5, 4, 7 };
int cooking[] = { 3, 6, 4 };
int babysitting[] = { 7, 6, 3 };
cout << "Number 1: Steve, Number 2: Mark, Number 3: Andrew.\n";
find(cleaning, "cleaner");
find(cooking, "cook");
find(babysitting, "babysitter");
/* This is to prevent the console application from quitting */
while (true)
{
}
}
I'm sure there is something wrong in the for and the while loop, but what?
If you're reading my code and some text or variable name seems foreign to you, chances are that I forgot to translate it (this is originally written in Italian).
Thanks for taking your time to read this.
EDIT: Thanks to #Tar I fixed the first part of the program, but the part which says The (name) that costs less is n. (arr[v]).still gives me a random number, I compiled and ran the program, the output is:
Number 1: Steve, Number 2: Mark, Number 3: Andrew.
4
The cheapest cleaner is number 4.
3
The cheapest cook is number 3.
3
The cheapest babysitter is number 7.
That is obviously wrong as it should say that the cheapest cleaner is number 2, the cheapest cook is number 1 and the cheapest babysitter is number 3.
PS: As soon as everything is fixed I will take the part which prints the cheapest price out.
The problem is within your first while loop in find:
while (arr[i]) // while the element at arr[i] is NOT 0
{
if (arr[i] < t)
{
t = arr[i];
}
i++;
}
Here you continuously evaluate elements in arr for whether they are not 0. This is not correct. You've declared your arrays as:
int cleaning[3] = { 5, 4, 7 };
int cooking[3] = { 3, 6, 4 };
int babysitting[3] = { 7, 6, 3 };
None of these contain 0, so your while loop will run indefinitely and you'll be reading past the memory for each array which is not good news.
Consider using std::vector instead, and see how much clearer and safer your code becomes:
#include <vector>
#include <iostream>
void find(const std::vector<int>& numbers)
{
auto t = 8;
// Look through each element in the container:
for(auto number : numbers)
{
if (number < t)
{
t = number;
}
}
std::cout << t << std::endl;
}
int main()
{
std::vector<int> cleaning = {5, 4, 7};
find(cleaning);
}
Above all, I want to make a statement: I am not an English-speaker, so if I said wrong words, please excuse me.
I think this question is not very difficult. I fixed your algorithm and output format. Actually, I almost rewrote it.
In my view, your code seems kind of naive. If you only learnt C++ syntax, there is a long way to study algorithm.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int find(const vector<int>& numbers) {
int minVul = numbers[0];
int rank = 0;
for (int i = 1; i < numbers.size(); i++)
{
if (minVul > numbers[i])
{
minVul = numbers[i];
rank = i;
}
}
return rank;
}
int main() {
vector<string> name = { "steve","mark","andrew" };
/* [0] = "Cost for steve"
[1] = "Cost for mark"
[2] = "Cost for andrew" */
vector<int> cleaning = { 5, 4, 7 };
vector<int> cooking = { 3, 6, 4 };
vector<int> babysitting = { 7, 6, 3 };
int cleaner = find(cleaning);
cout << "Cleaning:" << name[cleaner] << " costs least in " << cleaning[cleaner] << endl;
int cooker = find(cooking);
cout << "Cooking:" << name[cooker] << " costs least in " << cooking[cooker] << endl;
int babysitter = find(babysitting);
cout << "Babysitter:" << name[babysitter] << " costs least in " << babysitting[babysitter] << endl;
system("pause"); //This is a common skill to prevent the console application from quitting.
return 0;
}
Outputs:
Cleaning:mark costs least in 4
Cooking:steve costs least in 3
Babysitter:andrew costs least in 3

dividing duplicates by the counter of duplicates

the program i'm trying to write gets info from user, check duplicate in weight and count those duplicates.
For example,
{10, 40, 30, 40, 30} each 40 and 30 is duplicated 2 times
so it should be {10, 20, 15, 20, 15}
and this is my code:
struct Data {
int id;
double weight
}
std::sort(p, p + num, acompare);
for (int i = 0; i < num; i += counter) {
for (counter = 1; i + counter<num&& p[i + counter].weight== p[i].weight; )
counter++; // count consecutives dups
if (counter>1) { // if more than one, process the dups.
cntArr[i] = counter;
cntArr[counter] = counter;
} else
cntArr[i] = 1;
}
for (int i = 0; i < num; i++) {
cout << p[i].id << ":" << p[i].weight/ (double) cntArr[i] << endl;
}
and the result is like this
input :
1 100
2 100
3 100
4 80
5 80
output :
4 40
5 -9.79969e-08
1 33.3333
2 33.3333
3 -1.18744e-07
How do i fix this?
It's a bit hard to debug the specific problem in your code, as it isn't complete (can't copy-paste it to an editor and build it). In particular, not sure what are p, cntArray, and how they are initialized.
However, fundamentally, this code could be made shorter and more efficient. Instead of sorting (immediate Θ(n log(n)) complexity), use an std::unordered_map to store the multiplicity of each element. Shorter, fewer potential bugs, and (expected) linear complexity.
#include <vector>
#include <unordered_map>
#include <iostream>
#include <algorithm>
int main() {
const std::vector<int> a{10, 40, 30, 40, 30};
std::unordered_map<int, std::size_t> counts;
std::for_each(std::begin(a), std::end(a), [&](int e){ ++counts[e]; });
std::for_each(std::begin(a), std::end(a),
[&](int e){ std::cout << e / static_cast<double>(counts[e]) << std::endl; });
}
Outputs:
$ ./a.out
10
20
15
20
15

Adding Integers In A Vector

Ok, I have another challenge. I have a question that asks me to "Read a set of integers into a vector. Print the sum of each pair of adjacent elements . Change your program so that it prints out the sum of the first and last elements, followed by the sum of the second and second-to-last, and so on."
Currently I have managed to get it to add consecutive numbers, not exactly in pairs, but as close as I can get it.
The only operators I have learnt thus far for vectors, and what the question wants me to use are: v.empty(); v.size(); v.push_back(t); v[n]; v1 = v2; v1 = {a,b,c...}; v1 == v2; v1 != v2; <, <=, >, >=
Here is my code as it stands now:
#include <iostream>
#include <string>
#include <vector>
using std::string; using std::vector; using std::cout; using std::cin; using std::endl;
int main ()
{
vector<unsigned> numbers {5, 6, 7, 8, 9, 10, 11};
unsigned sum;
decltype(numbers.size()) count;
for (count = 0; count < numbers.size(); ++count){
sum = (numbers[count]++) + (numbers[count]);
cout << sum << " ";
}
}
So I can get it to add 5+6; 6+7; 7+8 etc... but as for each pair and all the rest, not 100% sure where to start. Any guidance will be greatly appreciated!
To print the sum of each pair of adjacent elements.
auto count = numbers.size();
for (auto i = 0; i < numbers.size()-1; i++)
{
std::cout << (numbers[i] + numbers[i+1]) << "\t";
}
prints out the sum of the first and last elements, followed by the sum of the second and second-to-last, and so on
for (auto i = 0; i < count/2; ++i)
{
std::cout << (numbers[i] + numbers[count - i -1]) << "\t";
}
Note: if vector has odd number, the middle one won't be calculated in second print
See sample output
Below two loops that print (1) sum of adjacent pairs and (2) the sum of opposite elements.
#include <cstddef>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main ()
{
vector<unsigned> numbers {5, 6, 7, 8, 9, 10, 11};
auto N = numbers.size();
std::cout << "first part\n";
for (size_t i = 1; i < N; ++i) {
std::cout << numbers[i-1] + numbers[i] << "\n";
}
std::cout << "second part\n";
for (size_t i = 0; i < (N - 1 - i); ++i) {
std::cout << numbers[i] + numbers[N - 1 - i] << "\n";
}
// in case you have an odd number of elements
if (N % 2 == 1) std::cout << numbers[N / 2] << "\n";
}
Output on LiveWorkSpace
I think your current code won't work for different examples. You need to change numbers[count]++ to numbers[count+1] for it to work, and change the loop's end condition to size()-1.
As for your other question, you should be able to do it if you only loop through half the vector and add the numbers of v[i] + v[v.size() - i - 1]
Edit: Added -1 to v[v.size() - i - 1] as suggested by borisbn in the comments
Hi I tried this on VS and it worked
vector <int> num;
num.push_back(5);
num.push_back(6);
num.push_back(7);
num.push_back(8);
num.push_back(9);
num.push_back(10);
int count = 0;
for(;count < (num.size()-1);count++)
{
int sum =0;
sum = num[count] + num[count+1];
cout<<sum<<endl;
}
for(int c =0; c < (num.size()-1);c++)
{
int altrsum = num[c]+ num[(num.size()-1)-c];
cout<<altrsum<<endl;
}
Hope this helps.

Given a list of primes and a factorization pattern, how to construct all numbers whose prime factorization matches the given pattern?

Though, I've tried to summarize the question in the title, I think it'll be better if I start off with an instance of the problem:
List of Primes = {2 3 5 7 11 13}
Factorization pattern = {1 1 2 1}
For the above input, the program should be generating the following list of numbers:
2.3.5^2.7
2.3.5^2.11
2.3.5^2.13
2.3.7^2.11
2.3.7^2.13
2.3.11^2.13
2.5.7^2.11
2.5.7^2.13
2.7.11^2.13
3.5.7^2.11
3.5.7^2.13
3.5.11^2.13
3.7.11^2.13
5.7.11^2.13
So far, I understand that since the length of the pattern is arbitrarily large (as is the list of primes), I need to use a recursive function to get all the combinations. What I'm really, really stuck is - how to formulate the function's arguments/when to call etc. This is what I've developed so far:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
static const int factors[] = {2, 3, 5, 7, 11, 13};
vector<int> vFactors(factors, factors + sizeof(factors) / sizeof(factors[0]));
static const int powers[] = {1, 1, 2, 1};
vector<int> vPowers(powers, powers + sizeof(powers) / sizeof(powers[0]));
// currPIdx [in] Denotes the index of Power array from which to start generating numbers
// currFidx [in] Denotes the index of Factor array from which to start generating numbers
vector<int> getNumList(vector<int>& vPowers, vector<int>& vFactors, int currPIdx, int currFIdx)
{
vector<int> vResult;
if (currPIdx != vPowers.size() - 1)
{
for (int i = currPIdx + 1; i < vPowers.size(); ++i)
{
vector<int> vTempResult = getNumList(vPowers, vFactors, i, currFIdx + i);
vResult.insert(vResult.end(), vTempResult.begin(), vTempResult.end());
}
int multFactor = pow((float) vFactors[currFIdx], vPowers[currPIdx]);
for (int i = 0; i < vResult.size(); ++i)
vResult[i] *= multFactor;
}
else
{ // Terminating the recursive call
for (int i = currFIdx; i < vFactors.size(); ++i)
{
int element = pow((float) vFactors[i], vPowers[currPIdx]);
vResult.push_back(element);
}
}
return vResult;
}
int main()
{
vector<int> vNumList = getNumList(vPowers, vFactors, 0, 0);
cout << "List of numbers: " << endl;
for (int i = 0; i < vNumList.size(); ++i)
cout << vNumList[i] << endl;
}
When I'm running the above, I'm getting a incorrect list:
List of numbers:
66
78
650
14
22
26
I've somehow run into a mental block, as I can't seem to figure out how to appropriately change the last parameter in the recursive call (which I believe is the reason my program isn't working)!!
It would be really great if anyone would be good enough to tweak my code with the missing logic (or even point me to it - I'm not looking for a complete solution!). I would be really grateful if you could restrict your answer to standard C++!
(In case someone notices that I'm missing out permutations of the given pattern, which would lead to other numbers such as 2.3.5.7^2 etc - don't worry, I intend to repeat this algorithm on all possible permutations of the given pattern by using next_permutate!).
PS: Not a homework/interview problem, just a part of an algorithm for a very interesting Project Euler problem (I think you can even guess which one :)).
EDIT: I've solved the problem on my own - which I've posted as an answer. If you like it, do upvote it (I can't accept it as the answer till it gets more votes than the other answer!)...
Forget about factorization for a moment. The problem you want to solve is having two lists P and F and finding all possible pairings (p,f) for p in P and f in F. This means you'll have |P| * |P|-1 ... * |P|-(|F|-1) possible pairings (assigning one from P to the first element of F, leaves |P|-1 possibilities to match the second element etc). You might want to separate that part of the problem in your code. If you recurse that way, the last step is choosing remaining element from P to the last element of F. Does that help? I must admit I don't understand your code well enough to provide an answer tailored to your current state, but that's how I'd approach it in general.
Well, I figured out this one on my own! Here's the code for it (which I hope is self-explanatory, but I can clarify in case anyone needs more details):
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
static const int factors[] = {2, 3, 5, 7, 11, 13};
vector<int> vFactors(factors, factors + sizeof(factors) / sizeof(factors[0]));
static const int powers[] = {1, 1, 2, 1};
vector<int> vPowers(powers, powers + sizeof(powers) / sizeof(powers[0]));
// idx - The index from which the rest of the factors are to be considered.
// 0 <= idx < Factors.size() - Powers.size()
// lvl - The lvl of the depth-first tree
// 0 <= lvl < Powers.size()
// lvlProd - The product till the previous level for that index.
void generateNumList
(
vector<int>& vPowers,
vector<int>& vFactors,
vector<int>& vNumList,
int idx,
int lvl,
long lvlProd
)
{
// Terminating case
if (lvl == vPowers.size() - 1)
{
long prod = pow((float) vFactors[idx], vPowers[lvl]) * lvlProd;
vNumList.push_back(prod);
}
else
{
// Recursive case
long tempLvlProd = lvlProd * pow((float) vFactors[idx], vPowers[lvl]);
for (int i = idx + 1; i < vFactors.size(); ++i)
generateNumList(vPowers, vFactors, vNumList, i, lvl + 1,
tempLvlProd);
}
}
vector<int> getNumList(vector<int>& vPowers, vector<int>& vFactors)
{
vector<int> vNumList;
for (int i = 0; i < vFactors.size(); ++i)
generateNumList(vPowers, vFactors, vNumList, i, 0, 1);
return vNumList;
}
int main()
{
vector<int> vNumList = getNumList(vPowers, vFactors);
cout << endl << "List of numbers (" << vNumList.size() << ") : " << endl;
for (int i = 0; i < vNumList.size(); ++i)
cout << vNumList[i] << endl;
}
The output of the above code (I had to work really long to get rid of duplicate entries algorithmically! ):
List of numbers (15) :
1050
1650
1950
3234
3822
9438
5390
6370
15730
22022
8085
9555
23595
33033
55055
real 0m0.002s
user 0m0.001s
sys 0m0.001s