3
\$\begingroup\$

This is a challenge question from codeeval.com:

Given a sequence, write a program to detect cycles within it. Input sample:

Your program should accept as its first argument a path to a filename containing a sequence of numbers (space delimited). The file can have multiple such lines. E.g

2 0 6 3 1 6 3 1 6 3 1

3 4 8 0 11 9 7 2 5 6 10 1 49 49 49 49

1 2 3 1 2 3 1 2 3

Output sample:

Print to stdout the first cycle you find in each sequence. Ensure that there are no trailing empty spaces on each line you print. E.g:

6 3 1

49

1 2 3

The cycle detection problem is explained more widely on wiki Constrains: The elements of the sequence are integers in range [0, 99] The length of the sequence is in range [0, 50]

Please let me know any improvements on this implementation.

#include<algorithm>
#include<unordered_map>
#include<iostream>
#include<set>
#include<fstream>
#include<sstream>
template<typename T>
class cyclicKeeper
{
 public:
 void push( T val)
 {
 cycles.push_back(val);
 cycleSet.emplace(val);
 }
 void clear()
 {
 for ( auto & x : cycles)
 {
 --counter[x];
 }
 cycles.clear();
 cycleSet.clear();
 }
 void incrementCounter(T val)
 {
 ++counter[val];
 }
 T counterValue(T val)
 {
 return counter[val];
 }
 void print()
 {
 std::vector<int> order( cycleSet.size());
 for( auto & x : cycleSet)
 {
 auto pos= std::find(std::begin(cycles), std::end(cycles),x);
 order[pos- std::begin(cycles)]=x;
 }
 for( auto &x : order)
 {
 std::cout<< x << " ";
 }
 std::cout<<"\n";
 }
 private:
 std::unordered_map<T,T> counter;
 std::vector<T> cycles;
 std::set<T> cycleSet; 
};
void processInputRecord(std::vector<int>& vec)
{
 cyclicKeeper<int> ck;
 for( auto & x : vec )
 {
 ck.incrementCounter(x);
 }
 int prev = 0;
 for( auto & x : vec )
 {
 if( ck.counterValue(x) > 1 )
 {
 if ( prev == 0)
 {
 prev = ck.counterValue(x);
 ck.push(x);
 }
 else if( prev == ck.counterValue(x) )
 {
 ck.push(x);
 }
 else
 {
 ck.clear();
 prev= ck.counterValue(x);
 ck.push(x);
 }
 }
 else
 {
 ck.clear();
 prev = 0;
 }
 }
 ck.print();
}
void readInputFile( std::string fileName )
{
 std::ifstream infile( fileName );
 std::vector<int> vec;
 std::string record;
 while( std::getline( infile, record ) )
 {
 std::istringstream iss(record);
 int temp = 0;
 while( iss >> temp )
 {
 vec.push_back(temp);
 }
 processInputRecord(vec);
 vec.clear();
 }
 infile.close();
}
int main( int argc, char* argv[] )
{
 if( argc < 2 )
 {
 std::cout << "Error: input file is missing " << "\n";
 exit( 0 );
 }
 std::ios_base::sync_with_stdio( false );
 readInputFile( argv[ 1 ]);
 return 0;
}
asked Jul 19, 2015 at 19:46
\$\endgroup\$
2
  • \$\begingroup\$ As I mention in the comments to JS1, the question is woefully underspecified. Is this all you have to go on? \$\endgroup\$ Commented Jul 20, 2015 at 20:31
  • \$\begingroup\$ @Veedrac Yes, Veedrac this is all. \$\endgroup\$ Commented Jul 21, 2015 at 1:03

1 Answer 1

4
\$\begingroup\$

Too complex

With the problem constrained to:

The elements of the sequence are integers in range [0, 99]
The length of the sequence is in range [0, 50]

the program should be very simple. Instead, you use an unordered_map, a vector, and a set, which is overkill. The problem could be solved with only a vector of size 50.

(Note: answer modified to find the cycle as clarified by the comments)

The vector of size 50 holds the input sequence. Starting at the end of the sequence, you only need to search backwards until you find a match for the last number of the sequence. This is because any cycle must end the sequence.

Simplified example

Here is the simplified code:

#define MAX_INPUT_LENGTH 50
void readInputFile( std::string fileName )
{
 std::ifstream infile( fileName );
 std::vector<int> inputValues(MAX_INPUT_LENGTH);
 std::string record;
 while( std::getline( infile, record ) )
 {
 std::istringstream iss(record);
 int i = 0;
 int value = 0;
 while( iss >> value )
 inputValues[i++] = value;
 int lastValue = inputValues[i-1];
 for (int j = i-2; j >= 0; j--) {
 if (inputValues[j] == lastValue) {
 // Found a cycle.
 for (j = j+1; j < i; j++)
 std::cout << inputValues[j] << " ";
 std::cout << "\n";
 break;
 }
 }
 }
 infile.close();
}
answered Jul 20, 2015 at 17:15
\$\endgroup\$
5
  • \$\begingroup\$ What about 1 2 3 1 4 2 3 1 4 (although the Wiki link suggests the sequence is made from an iterated function, so maybe not)? \$\endgroup\$ Commented Jul 20, 2015 at 17:39
  • \$\begingroup\$ @Veedrac What about your sequence? The code I wrote outputs 1 2 3 for it. Is that not correct? Also, I edited my answer to show that your program could not find a cycle in 3 2 1 3. \$\endgroup\$ Commented Jul 20, 2015 at 19:20
  • \$\begingroup\$ 1 2 3 is not a cycle in 1 2 3 1 4 2 3 1 4 - the cycle is 2 3 1 4. There's also a strong implication that cycles must contain at least two "copies"; else 2 0 6 3 1 6 3 1 6 3 1 would be a cycle in 2 0 6 3 1 6 3 1 6 3 1. I'll admit the question is badly-formed, but I'm not sold on your reading of it. \$\endgroup\$ Commented Jul 20, 2015 at 20:28
  • 1
    \$\begingroup\$ @Veedrac So if I use your interpretation of a cycle, then I think the sequence should be infinite. I don't think the question is well formed. For example, is there a cycle in: 1 2 3 1 2 3 4? If we assume that the sequence doesn't have to be infinite, then it should at least end in the cycle. In which case, you can start at the back end and look for the first repeat of the last number of the sequence to find the cycle. \$\endgroup\$ Commented Jul 20, 2015 at 20:38
  • 1
    \$\begingroup\$ @Veedrac According to the wikipedia article linked by the question, the series of numbers is a sequence of iterated function values. This means that a sequence such as 1 2 3 1 4 is not allowed because 1 must always be followed by the same number (in this case 2). So I believe my original solution holds, although the new solution I added also works and is even shorter. \$\endgroup\$ Commented Jul 20, 2015 at 20:50

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.