C++ Program for Generating Lyndon words of length n

Given an integer n and an array of characters S, the task is to generate Lyndon words of length n having characters from S.

A Lyndon word is a string which is strictly less than all of its rotations in lexicographic order. For example, the string β€œ012” is a Lyndon word as it is less than its rotations β€œ120” and β€œ201”, but β€œ102” is not a Lyndon word as it is greater than its rotation β€œ021”.
Note: β€œ000” is not considered to be a Lyndon word as it is equal to the string obtained by rotating it.

Examples:

Input: n = 2, S = {0, 1, 2}
Output: 01
02
12
Other possible strings of length 2 are β€œ00”, β€œ11”, β€œ20”, β€œ21”, and β€œ22”. All of these are either
greater than or equal to one of their rotations.

Input: n = 1, S = {0, 1, 2}
Output: 0
1
2

Approach: There exists an efficient approach to generate Lyndon words which was given by Jean-Pierre Duval, which can be used to generate all the Lyndon words upto length n in time proportional to the number of such words. (Please refer to the paper β€œAverage cost of Duval’s algorithm for generating Lyndon words” by Berstel et al. for the proof)
The algorithm generates the Lyndon words in a lexicographic order. If w is a Lyndon word, the next word is obtained by the following steps:

  1. Repeat w to form a string v of length n, such that v[i] = w[i mod |w|].
  2. While the last character of v is the last one in the sorted ordering of S, remove it.
  3. Replace the last character of v by its successor in the sorted ordering of S.

For example, if n = 5, S = {a, b, c, d}, and w = β€œadd” then we get v = β€œaddad”.
Since β€˜d’ is the last character in the sorted ordering of S, we remove it to get β€œadda”
and then replace the last β€˜a’ by its successor β€˜b’ to get the Lyndon word β€œaddb”.

Below is the implementation of the above approach:

C++




// C++ implementation of 
// the above approach 
#include<bits/stdc++.h>
using namespace std;
  
int main()
{
    int n = 2;
    char S[] = {'0', '1', '2' };
    int k = 3;
    sort(S, S + 3);
      
    // To store the indices 
    // of the characters 
    vector<int> w;
    w.push_back(-1);
      
    // Loop till w is not empty     
    while(w.size() > 0)
    {
          
        // Incrementing the last character
        w[w.size()-1]++;
        int m = w.size();
        if(m == n)
        {
            string str;
            for(int i = 0; i < w.size(); i++)
            {
                str += S[w[i]];
            }
            cout << str << endl;
        }
      
        // Repeating w to get a 
        // n-length string
        while(w.size() < n)
        {
            w.push_back(w[w.size() - m]);
        }
      
        // Removing the last character 
        // as long it is equal to 
        // the largest character in S 
        while(w.size() > 0 && w[w.size() - 1] == k - 1)
        {
            w.pop_back();
        }
    }
    return 0;
}
  
// This code is contributed by AdeshSingh1


Output:

01
02
12

Please refer complete article on Generating Lyndon words of length n for more details!