reverse iteration of map in c++ missing out the first element - c++

I have a code where I am reverse iterating a map in C++. For n pairs in map, sometimes the map prints out n pairs, sometimes n-1 pairs.
for test case
4 2
2 1
3 5
2 3
1 5
it prints 4 hi's, for the next case 3 hi's
4 1
0 2
0 3
3 5
0 6
My code:
include cmath, cstdio, vector, iostream, map, algorithm, using namespace std;
int main() {
int n,f;
cin >> n >> f;
int k[n],l[n],dif[n];
map<int,int> m;
map<int,int>::reverse_iterator it;
for (int i=0;i<n;i++){
scanf("%d %d\n",&k[i],&l[i]);
dif[i] = l[i]-k[i];
m.insert(make_pair(dif[i],l[i]));
}
int a = 0;
int sum = 0;
for(it = m.rbegin(); it != m.rend(); ++it ) {
cout << "hi" << endl;
int article = it->second - it->first;
int people = it->second;
if (a < f and article!=0){
a++;
if (2*article > people){
sum = sum + people;
} else {
sum = sum + (2*article);
}
} else {
if (article > people){
sum = sum + people;
} else {
sum = sum + article;
}
}
}
cout << sum;
return 0;
}

This has nothing to do with reverse iteration, it would be the same with forward iteration. A map has a pair of a key and a value. Each key can only be included in the map once. When you insert the same key again the previous value is overwritten. In your second test case you are setting the key 0 three times:
4 1
0 2 <--
0 3 <--
3 5
0 6 <--
So your map actually only has three values, so the three "Hi" are correct. In your first example you overwrite key 2 only twice, so the four "Hi". Maybe a map is not the correct container you are looking for.

Related

remove an element from the back of a vector after shuffling it c++

so the purpose of the code is to shuffle a vector, then print a random number from the vector, and then delete that same number so it won't repeat.
what I did is:
there is an initialized vector called songs, first I used random_device to make a random func.
I initialized an iterator to the back of the vector.
I shuffled the vector
Print
remove the last element that I printed (after shuffling).
The problem is when I do songs.pop_back(); it removes the last element from the original vector and not from the shuffled one, so it makes numbers coming back that way.
and I get an error.
code:
int getSong(int n, vector<int> songs, vector<int>::iterator iter) {
random_device random;
shuffle(songs.begin(), songs.end(), random);
for (int j = 0; j < n; j++) {
cout << songs[j] << " ";
}
iter = songs.end() -1 ;
int song = *iter;
iter--;
return song;
}
int main() {
vector<int> songs = { 1,2,3,4,5,6,7,8,9 };
int n = songs.size();
vector<int>::iterator iter;
for (int i = 0; i < n; n--) {
int l = getSong(n, songs, iter);
cout << "The song number is:" << l << "\n" << endl;
songs.pop_back();
}
return 0;
}
the output is:
Thank you!
I would write something like this instead. It is sort of wasteful but I wanted to keep your original program structure.
First, you need to pass a reference to the vector with std::vector<int>& if you want to modify its contents in the function. If your intent was to keep the original vector then yes, you just pass by value. But as you need to remove the last value in the main function, I figured this was the only way.
Second the iterator is not necessary. You can just remove that.
Last, you dont need to pass the size as the vector itself contains the size.
The use of random_device is somewhat awkward as random_shuffle would be cleaner - but again I tried to change your code minimally.
int getSong( vector<int>& songs ) {
random_device random;
shuffle(songs.begin(), songs.end(), random);
for ( int song : songs ) {
cout << song << " ";
}
cout << endl;
return *songs.rbegin();
}
In regards to the main loop, checking for empty() is cleaner than a loop through the size - it's more immune to edge cases.
int main() {
vector<int> songs = { 1,2,3,4,5,6,7,8,9 };
while( !songs.empty() ) {
int l = getSong(songs);
cout << "The song number is:" << l << "\n" << endl;
songs.pop_back();
}
return 0;
}
https://godbolt.org/z/oWbxvMjE3
Produces:
Program stdout
5 3 6 8 1 9 7 4 2
The song number is:2
7 3 5 8 6 9 1 4
The song number is:4
6 1 9 8 3 5 7
The song number is:7
3 6 1 5 8 9
The song number is:9
6 8 5 3 1
The song number is:1
8 5 3 6
The song number is:6
3 5 8
The song number is:8
3 5
The song number is:5
3
The song number is:3

C++ push_back in vectors

I built a recursive function that reads a vector as input and returns a new vector in which every two consecutive elements are switched. For example input: 1 2 3 4 5 6 and output: 2 1 4 3 6 5. The thing I don't get is that when I write the function this way:
vector<int> reverse(vector<int> v) {
if (v.size() < 2)
return v;
else
{
int pos1 = v.at(0); //= 1
int pos2 = v.at(1); //= 2
v.erase(v.begin()); //v = 2 3 4 5 6
v.erase(v.begin()); //v = 3 4 5 6
vector<int> rev = reverse(v);
rev.push_back(pos2); //rev = 2
rev.push_back(pos1); //rev = 2 1
return rev;
}
}
i get 6 5 4 3 2 1. I know the vector::push_back() adds the elements at the end of the vector, so why not 2 1 4 3 6 5? When I wrote it this way it gave me the good answer though (2 1 4 3 6 5) but idk why:
vector<int> reverse(vector<int> v) {
if (v.size() < 2)
return v;
else
{
int pos1 = v.at(v.size() - 2); //= 5
int pos2 = v.at(v.size() - 1); //= 6
v.pop_back(); //v = 1 2 3 4 5
v.pop_back(); //v = 1 2 3 4
vector<int> rev = reverse(v); //call the recursive function
rev.push_back(pos2); //rev = 5
rev.push_back(pos1); //rev = 6 5
return rev;
}
}
The main() function is this:
int main() {
vector<int> w;
int zahl;
cout << "Please give the vector or any letter to end the input: "<< endl;
while (cin >> zahl)
{
w.push_back(zahl);
}
for (int elem : reverse(w))
{
cout << elem << ", ";
}
return 0;
}
It's an easy fix.
The problem with your code is that the recursive step does not correctly translate a correctly constructed sub-result to a slightly larger one.
You would want to do:
// Correctly create the head of the result.
vector<int> rev = {pos2, pos1};
// Now you want to handle the tail, and assuming the output of reverse
// is correct for smaller lists, this would be achieved by appending
// the rest.
const auto sub = reverse(v);
rev.insert(rev.end(), sub.begin(), sub.end());
This ensures that if your list starts with 1 2, it would turn into a list with 2 1, followed by a correctly processed tail.
Your second code worked because you were processing the sequence in reverse, so your recursive step was in fact correct.
The result you obtain is incorrect because in the last call to your function you return an empty vector, and then you push at the back of this vector your last pair of numbers inverted, so 6,5, so you do proceding back in the call stack.
Let's have a look to what you have at every call (first call, second call, ecc.):
v=[1,2,3,4,5,6] ->recursive call
v=[3,4,5,6] ->recursive call
v=[5,6] ->recursive call
v=[] ->return empty vector
rev=[], push back the first two elements of v in reverse order, so rev=[6,5] ->return rev
rev=[6,5], push back the first two elements of v in reverse order, so rev=[6,5,4,3] ->return rev
rev=[6,5,4,3], push back the first two elements of v in reverse order, so rev=[6,5,4,3,2,1]
For this reason, you need first to have a vector with the first two numbers reversed and then attach the processed tail, as suggested above.
Please note that you are constructing copies of the vector every time you call the function. You can create a reversed copy without modifying the copy of the argument given as argument. I would use iterators instead, so that every time your function "sees" a smaller portion of the original vector, without touching it. Here an implementation:
vector<int> reverse(vector<int>::const_iterator begin, vector<int>::const_iterator end) {
if (begin==end-1) //the vector has an odd number of elements, let's append the last element
return vector<int>(1, *(end-1));
else if(begin>=end) //the vector has en even number of elements
return vector<int>();
else
{
vector<int> pairWiseReversed({*(begin+1), *begin});
vector<int> tail=reverse(begin+2, end);
pairWiseReversed.insert(pairWiseReversed.end(), tail.begin(), tail.end());
return pairWiseReversed;
}
}
vector<int> buildReversed(const vector<int>& input){
return reverse(input.begin(), input.end());
}
And here a main:
int main() {
vector<int> v{1,2,3,4,5,6};
cout<<"Input vector"<<endl;
for(auto n:v)
cout<<n<<" ";
cout<<endl;
vector<int> res=buildReversed(v);
cout<<"Output vector"<<endl;
for(auto n:res)
cout<<n<<" ";
cout<<endl;
return 0;
}

C++ Array (disregarding a repeat number)

I am a beginner programmer and I need some assistance.
I need to write a program that reads an array of 10 numbers from a user, then scans it and figures out the most common number/s in the array itself and prints them. If there is only one number that is common in the array, only print that number. But, if there's more than one number that appears more than once, print them also in the order they appear in in the array.
For example- 1 2 3 3 4 5 6 7 8 9 - output would be 3
For- 1 2 3 4 1 2 3 4 5 6 - output would be 1 2 3 4
for- 1 1 1 1 2 2 2 3 3 4 - output would be 1 2 3
Now, the problem I've been running into, is that whenever I have a number that repeats more than twice (see third example above), the output I'm getting is the number of iterations of the loop for that number and not only that number once.
Any assistance would be welcome.
Code's attached below-
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int array [10], index, checker, common;
main ()
{
for (index=0; index<10; index++)
{
cin >> array [index];
}
for (index=0; index<10; index++)
{
int tempcount=0;
for (checker=(index+1);checker<10;checker++)
{
if (array[index]==array[checker])
tempcount++;
}
if (tempcount>=1)
cout << array[index]<<" ";
}
return 0;
}
Use appropriate data structures for the task.
Create a std::unordered_map that maps value to number_of_occurrences, and make a single pass over the input data.
Then create another map from number_of_occurrences to value. Sort it, in descending order. Report the first value, plus any additional ones that occurred as many times as the first did.
The reason you are having problems is that anytime a number appears two times or more it will print out. A solution is that you create another variable maxCount, then find the maximum times a number appears. Then loop through the array and print out all the numbers that appears the maximum amount of times.
Hope this helps.
Jake
Rather than writing you a solution, I will try to give you some hints that you can hopefully use to correct your code. Try to keep track of the following things:
Remember the position of the first occurrence of each distinct number in the array.
Count the number of times each number appears
and combine the two to get your solution.
EDIT:
int array[] = {1, 2, 3, 4, 1, 2, 3, 4, 5, 6};
int first [11], cnt[11];
for(int i = 0; i < 11; i++){
first[i] = -1;
cnt[i] = 0;
}
int max = 0;
for(int i = 0; i < 10; i++){
cnt[array[i]]++;
if(max < array[i]) max = array[i];
}
for(int i = 0; i <= max; i++){
if(cnt[i] > 1 && first[i] == -1) {
printf(" %d", i);
first[i] = i;
}
}
You could do something like this. At any index in the array look for previous occurences of that element. If you find that that it is the first occurence of that element, you only need to look if there is an occurence of that element ahead in the array.
Lastly display the element whose frequency(here num) would be greater than 1.
for (int i = 0; i < 10; i++)
{
int presentBefore = 0;
for (int j = 0; j < i; j++) //if any previous occurence of element
{
if (array[i] == array[j]) presentBefore++;
}
if (presentBefore == 0)//if first occurence of the element
{
int num = 1;
for (int j = i + 1; j < 8; j++)// if occurences ahead in the array
{
if (array[i] == array[j]) num++;
}
if(num>1)cout<<array[i]<<" ";
}
}
Here is another solution using STL and std::set.
#include <iostream>
#include <algorithm>
#include <set>
#include <iterator>
int main()
{
int array[12] = { 1, 2, 3, 1, 2, 4, 5, 6, 3, 4, 1, 2 };
std::set<int> dupes;
for (auto it = std::begin(array), end = std::end(array); it != end; ++it)
{
if (std::count(it, end, *it) > 1 && dupes.insert(*it).second)
std::cout << *it << " ";
}
return 0;
}
Prints:
1 2 3 4
I will try to explain how this works:
The original array is iterated from start to finish (BTW as you can see it can be any length, not just 10, as it uses iterators of beginning and end)
We are going to store duplicates which we find with std::count in std::set
We count from current iterator until the end of the array for efficiency
When count > 1, this means we have a duplicate so we store it in set for reference.
std::set has unique keys, so trying to store another number that already exists in set will result in insert .second returning false.
Hence, we print only unique insertions, which appear to be in the order of elements appearing in the array.
In your case you can use class std::vector which allows you to Erase elements, resize the array...
Here is an example I provide which produces what you wanted:
1: Push the values into a vector.
2: Use 2 loops and compare the elements array[i] and array[j] and if they are identical push the the element j into a new vector. Index j is always equal to i + 1 in order to avoid comparing the value with itself.
3- Now you get a vector of the repeated values in the temporary vector; You use 2 loops and search for the repeated values and erase them from the vector.
4- Print the output.
NB: I overloaded the insertion operator "<<" to print a vector to avoid each time using a loop to print a vector's elements.
The code could look like :
#include <iostream>
#include <vector>
std::ostream& operator << (std::ostream& out, std::vector<int> vecInt){
for(int i(0); i < vecInt.size(); i++)
out << vecInt[i] << ", ";
return out;
}
int main() {
std::vector< int > vecInt;
//1 1 1 1 2 2 2 3 3 4
vecInt.push_back(1);
vecInt.push_back(1);
vecInt.push_back(1);
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(2);
vecInt.push_back(2);
vecInt.push_back(3);
vecInt.push_back(3);
vecInt.push_back(4);
std::vector<int> vecUniq;
for(int i(0); i < vecInt.size(); i++)
for(int j(i + 1); j < vecInt.size(); j++)
if(vecInt[i] == vecInt[j])
vecUniq.push_back(vecInt[j]);
std::cout << vecUniq << std::endl;
for(int i = 0; i < vecUniq.size(); i++)
for(int j = vecUniq.size() - 1 ; j >= 0 && j > i; j--)
if(vecUniq[i] == vecUniq[j])
vecUniq.erase(&vecUniq[j]);
std::cout << vecUniq << std::endl;
std::cout << std::endl;
return 0;
}
The input: 1 2 3 3 4 5 6 7 8 9
The output: 3
The input: 1 2 3 4 1 2 3 4 5 6
The output: 1 2 3 4
The input: 1 1 1 1 2 2 2 3 3 4
The output: 1 2 3
For this problem, you can use a marking array that will count the number of times you a digit is visited by you, it's just like counting sort. let's first see the program :
#include <iostream>
using namespace std;
int print(int a[],int b[])
{
cout<<"b :: ";
for (int index=0;index<10;index++)
{
cout<<b[index]<<" ";
}
cout<<endl;
}
int main ()
{
int a[10],b[11], index, checker, common;
for (index=0; index<10; index++)
{
cin >> a [index];
b[index] = 0;
}
b[10] =0;
for (index=0;index<10;index++)
{
b[a[index]]++;
if (b[a[index]] == 2)
cout<<a[index];
//print(a,b);
}
return 0;
}
As you can see that I have used array b as marking array which counts the time a number is visited.
The size of array b depends upon what is the largest number you are going to enter, I have set the size of array b to be of length 10 that b[11] as your largest number is 10. Index 0 is of no use but you need not worry about it as it will be not pointed until your input has 0.
Intially all elements in array in b is set 0.
Now assume your input to be :: 1 2 3 4 1 2 3 4 5 6
Now value of b can be checked after each iteration by uncommenting the print function line::
b :: 0 1 0 0 0 0 0 0 0 0 ....1
b :: 0 1 1 0 0 0 0 0 0 0 ....2
b :: 0 1 1 1 0 0 0 0 0 0 ....3
b :: 0 1 1 1 1 0 0 0 0 0 ....4
b :: 0 2 1 1 1 0 0 0 0 0 ....5
b :: 0 2 2 1 1 0 0 0 0 0 ....6
b :: 0 2 2 2 1 0 0 0 0 0 ....7
b :: 0 2 2 2 2 0 0 0 0 0 ....8
b :: 0 2 2 2 2 1 0 0 0 0 ....9
b :: 0 2 2 2 2 1 1 0 0 0 ....10
In line 5 you can b's at index 1 has value 2 so it will print 1 that is a[index].
And array a's element will be printed only when it is repeated first time due to this line if(b[a[index]] == 2) .
This program uses the idea of counting sort so if you want you can check counting sort.

Algorithm for Combinations of given numbers with repetition? C++

So I N - numbers I have to input, and I got M - numbers of places for those numbers and I need to find all combinations with repetition of given numbers.
Here is example:
Let's say that N is 3(I Have to input 3 numbers), and M is 4.
For example let's input numbers: 6 11 and 533.
This should be result
6,6,6,6
6,6,6,11
6,6,6,533
6,6,11,6
...
533,533,533,533
I know how to do that manualy when I know how much is N and M:
In example where N is 3 and M is 4:
int main()
{
int N = 3;
int M = 4;
int *numbers = new int[N + 1];
for (int i = 0; i < N; i++)
cin >> numbers[i];
for (int a = 0; a < N; a++)
for (int b = 0; b < N; b++)
for (int c = 0; c < N; c++)
for (int d = 0; d < N; d++)
{
cout << numbers[a] << " " << numbers[b] << " " << numbers[c] << " " << numbers[d] << endl;
}
return 0;
}
But how can I make algorithm so I can enter N and M via std::cin and I get correct resut?
Thanks.
First one short tip: don't use "new" or C-style arrays in C++ when we have RAII and much faster data structures.
For the solution to your problem I would suggest making separate function with recursion. You said you know how to do it manually so the first step in making it into algorithm is to tear down you manual solution step by step. For this problem when you solve it by hand you basically start with array of all first numbers and then for last position you just loop through available numbers. Then you go to the second last position and again loop through available numbers just now with the difference that for every number there you must also repeat the last spot number loop. Here is the recursion. For every "n"th position you must loop through available numbers and for every call the same function for "n+1"th number.
Here is a simplified solution, leaving out the input handling and exact print to keep code shorter and more focused on the problem:
#include <vector>
#include <iostream>
void printCombinations(const std::vector<int>& numbers, unsigned size, std::vector<int>& line) {
for (unsigned i = 0; i < numbers.size(); i++) {
line.push_back(numbers[i]);
if (size <= 1) { // Condition that prevents infinite loop in recursion
for (const auto& j : line)
std::cout << j << ","; // Simplified print to keep code shorter
std::cout << std::endl;
line.erase(line.end() - 1);
} else {
printCombinations(numbers, size - 1, line); // Recursion happens here
line.erase(line.end() - 1);
}
}
}
int main() {
std::vector<int> numbers = {6, 11, 533};
unsigned size = 4;
std::vector<int> line;
printCombinations(numbers, size, line);
return 0;
}
If you have any questions feel free to ask.
Totally there is no need for recursion here. This is a typical job for dynamic programming. Just get the first solution right for n = 1 (1 slot is available) which means the answer is [[6],[11],[533]] and then move on one by one by relying on the one previously memoized solution.
Sorry that i am not fluent in C, yet in JS this is the solution. I hope it helps.
function combosOfN(a,n){
var res = {};
for(var i = 1; i <= n; i++) res[i] = res[i-1] ? res[i-1].reduce((r,e) => r.concat(a.map(n => e.concat(n))),[])
: a.map(e => [e]);
return res[n];
}
var arr = [6,11,533],
n = 4;
console.log(JSON.stringify(combosOfN(arr,n)));
Normally the easiest way to do dynamic nested for loops is to create your own stack and use recursion.
#include <iostream>
#include <vector>
void printCombinations(int sampleCount, const std::vector<int>& options, std::vector<int>& numbersToPrint) {
if (numbersToPrint.size() == sampleCount) {
// got all the numbers we need, print them.
for (int number : numbersToPrint) {
std::cout << number << " ";
}
std::cout << "\n";
}
else {
// Add a new number, iterate over all possibilities
numbersToPrint.push_back(0);
for (int number : options) {
numbersToPrint.back() = number;
printCombinations(sampleCount, options, numbersToPrint);
}
numbersToPrint.pop_back();
}
}
void printCombinations(int sampleCount, const std::vector<int>& options) {
std::vector<int> stack;
printCombinations(sampleCount, options, stack);
}
int main()
{
printCombinations(3, {1,2,3});
}
output
1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3
2 1 1
2 1 2
2 1 3
2 2 1
2 2 2
2 2 3
2 3 1
2 3 2
2 3 3
3 1 1
3 1 2
3 1 3
3 2 1
3 2 2
3 2 3
3 3 1
3 3 2
3 3 3
Here is an algorithm to solve this, that does't use recursion.
Let's say n=2 and m=3. Consider the following sequence that corresponds to these values:
000
001
010
011
100
101
110
111
The meaning of this is that when you see a 0 you take the first number, and when you see a 1 you take the second number. So given the input numbers [5, 7], then 000 = 555, 001=557, 010=575 etc.
The sequence above looks identical to representing numbers from 0 to 7 in base 2. Basically, if you go from 0 to 7 and represent the numbers in base 2, you have the sequence above.
If you take n=3, m=4 then you need to work in base 3:
0000
0001
0002
0010
0011
0012
....
So you go over all the numbers from 0 to 63 (4^3-1), represent them in base 3 and follow the coding: 0 = first number, 1 = second number, 2 = third number and 3 = fourth number.
For the general case, you go from 0 to M^N-1, represent each number in base N, and apply the coding 0 = first number, etc.
Here is some sample code:
#include <stdio.h>
#include <math.h>
void convert_to_base(int number, char result[], int base, int number_of_digits) {
for (int i = number_of_digits - 1; i >= 0; i--) {
int remainder = number % base;
number = number / base;
result[i] = '0' + remainder;
}
}
int main() {
int n = 2, m = 3;
int num = pow(n, m) - 1;
for (int i = 0; i <= num; i++) {
char str[33];
convert_to_base(i, str, n, m);
printf("%s\n", str);
}
return 0;
}
Output:
000
001
010
011
100
101
110
111

Iterated Difference

This is an spoj problem. It works, but It's too slow.
Here is the question:
Iterated Difference
You are given a list of N non-negative integers a(1), a(2), ... ,
a(N). You replace the given list by a new list: the k-th entry of the
new list is the absolute value of a(k) - a(k+1), wrapping around at
the end of the list (the k-th entry of the new list is the absolute
value of a(N) - a(1)). How many iterations of this replacement are
needed to arrive at a list in which every entry is the same integer?
For example, let N = 4 and start with the list (0 2 5 11). The successive iterations are:
2 3 6 11
1 3 5 9
2 2 4 8
0 2 4 6
2 2 2 6
0 0 4 4
0 4 0 4
4 4 4 4
Thus, 8 iterations are needed in this example.
Input
The input will contain data for a number of test cases. For each case,
there will be two lines of input. The first line will contain the
integer N (2 <= N <= 20), the number of entries in the list. The
second line will contain the list of integers, separated by one blank
space. End of input will be indicated by N = 0.
Output
For each case, there will be one line of output, specifying the case
number and the number of iterations, in the format shown in the sample
output. If the list does not attain the desired form after 1000
iterations, print 'not attained'.
Sample Input
4
0 2 5 11
5
0 2 5 11 3
4
300 8600 9000 4000
16
12 20 3 7 8 10 44 50 12 200 300 7 8 10 44 50
3
1 1 1
4
0 4 0 4
0
Sample Output
Case 1: 8 iterations
Case 2: not attained
Case 3: 3 iterations
Case 4: 50 iterations
Case 5: 0 iterations
Case 6: 1 iterations
I'm not sure of what to do to make it faster. I tried using arrays, but I get all sorts of problems trying to allocate the memory and set one array to another.
How can I make it faster? Here's my code:
#include <iostream>
#include <vector>
#include <cmath>
#include <sstream>
#include <string>
using namespace std;
bool checker(vector<int>& nums2) {
int n = nums2[0];
for (int i = 1; i < nums2.size(); i++)
{
if (n != nums2[i])
return false;
}
return true;
}
vector<int> iterate(vector<int>& nums, int& iter, bool& attained) {
if (iter == 1000) {
attained = false;
return nums;
}
vector<int> nums2;
for (int i = 0; i < nums.size(); i++) {
if (i == nums.size() - 1)
nums2.push_back((int)abs((double)nums[i] - (double)nums[0]));
else
nums2.push_back((int)abs((double)nums[i] - (double)nums[i + 1]));
}
iter++;
return nums2;
}
int main()
{
int N = -1, count = 1;
while (1) {
int num = 0;
vector<int> nums;
string List = "";
stringstream ss;
cin >> N;
if (N == 0)
break;
cin.ignore();
cin.clear();
getline(cin, List);
ss << List;
while (ss >> num) {
nums.push_back(num);
}
int iterations = 0;
bool attained = true;
while (!checker(nums)) {
nums = iterate(nums, iterations, attained);
}
if (!attained)
cout << "case " << count << ": not attained";
else
cout << "case " << count << ": " << iterations << " iterations" << endl;
count++;
}
}
I fixed it. It was a problem with the while loop in the main function. The condition was:
while (!checker(nums)) { ... }
It would stay in the loop and repeatedly call the iterate function because if it is not attainable, then the checker will always be false. So changing the condition to:
while (!checker(nums) && attained) { ... }
would break the loop if it was not attainable.
Basically, it was just getting stuck on doing the same thing over and over; it wasn't actually slow.
Thanks, xan, for your answer.
If you want it to be a little faster you should work on debugging your array variation to avoid the vector allocations. If you want it to be a lot faster you need to do some analysis of the problem to find a better algorithm. For instance, if you see the same list twice you're in a loop and will exceed 1000 iterations. And the result will be the same if you rotate the list, which you can consider when checking for a repeated list.
Your implementation executes 1000 iterations in 25ms on my mainstream lapton. Fixed one, because there's a bug and case 2 will execute forever.
To do faster you can reuse the same vector and modify it in place, your iterator() function signature would look like:
void iterate(vector<int>& nums);
This version takes 7ms on my machine, because it doesn't allocate memory in loop.