Given an integer n and a set of characters A of size k, find a string S such that every possible string on A of length n appears exactly once as a substring in S. Such a string is called de Bruijn sequence.
Examples:
Input: n = 3, k = 2, A = {0, 1)
Output: 0011101000
All possible strings of length three (000, 001, 010, 011, 100, 101, 110 and 111) appear exactly once as sub-strings in A.Input: n = 2, k = 2, A = {0, 1)
Output: 01100
Approach:
We can solve this problem by constructing a directed graph with kn-1 nodes with each node having k outgoing edges. Each node corresponds to a string of size n-1. Every edge corresponds to one of the k characters in A and adds that character to the starting string.
For example, if n=3 and k=2, then we construct the following graph:
- The node ’01’ is connected to node ’11’ through edge ‘1’, as adding ‘1’ to ’01’ (and removing the first character) gives us ’11’.
- We can observe that every node in this graph has equal in-degree and out-degree, which means that a Eulerian circuit exists in this graph.
- The Eulerian circuit will correspond to a de Bruijn sequence as every combination of a node and an outgoing edge represents a unique string of length n.
- The de Bruijn sequence will contain the characters of the starting node and the characters of all the edges in the order they are traversed in.
- Therefore the length of the string will be kn+n-1. We will use Hierholzer’s Algorithm to find the Eulerian circuit. The time complexity of this approach is O(kn).
Below is the implementation of the above approach:
// C++ implementation of // the above approach #include <bits/stdc++.h> using namespace std;
unordered_set<string> seen; vector< int > edges;
// Modified DFS in which no edge // is traversed twice void dfs(string node, int & k, string& A)
{ for ( int i = 0; i < k; ++i) {
string str = node + A[i];
if (seen.find(str) == seen.end()) {
seen.insert(str);
dfs(str.substr(1), k, A);
edges.push_back(i);
}
}
} // Function to find a de Bruijn sequence // of order n on k characters string deBruijn( int n, int k, string A)
{ // Clearing global variables
seen.clear();
edges.clear();
string startingNode = string(n - 1, A[0]);
dfs(startingNode, k, A);
string S;
// Number of edges
int l = pow (k, n);
for ( int i = 0; i < l; ++i)
S += A[edges[i]];
S += startingNode;
return S;
} // Driver code int main()
{ int n = 3, k = 2;
string A = "01" ;
cout << deBruijn(n, k, A);
return 0;
} |
// Java implementation of // the above approach import java.util.*;
class GFG
{ static Set<String> seen = new HashSet<String>();
static Vector<Integer> edges = new Vector<Integer>();
// Modified DFS in which no edge
// is traversed twice
static void dfs(String node, int k, String A)
{
for ( int i = 0 ; i < k; ++i)
{
String str = node + A.charAt(i);
if (!seen.contains(str))
{
seen.add(str);
dfs(str.substring( 1 ), k, A);
edges.add(i);
}
}
}
// Function to find a de Bruijn sequence
// of order n on k characters
static String deBruijn( int n, int k, String A)
{
// Clearing global variables
seen.clear();
edges.clear();
String startingNode = string(n - 1 , A.charAt( 0 ));
dfs(startingNode, k, A);
String S = "" ;
// Number of edges
int l = ( int ) Math.pow(k, n);
for ( int i = 0 ; i < l; ++i)
S += A.charAt(edges.get(i));
S += startingNode;
return S;
}
private static String string( int n, char charAt)
{
String str = "" ;
for ( int i = 0 ; i < n; i++)
str += charAt;
return str;
}
// Driver code
public static void main(String[] args)
{
int n = 3 , k = 2 ;
String A = "01" ;
System.out.print(deBruijn(n, k, A));
}
} // This code is contributed by 29AjayKumar |
# Python3 implementation of # the above approach import math
seen = set ()
edges = []
# Modified DFS in which no edge # is traversed twice def dfs( node, k, A):
for i in range (k):
str = node + A[i]
if ( str not in seen):
seen.add( str )
dfs( str [ 1 :], k, A)
edges.append(i)
# Function to find a de Bruijn sequence # of order n on k characters def deBruijn(n, k, A):
# Clearing global variables
seen.clear()
edges.clear()
startingNode = A[ 0 ] * (n - 1 )
dfs(startingNode, k, A)
S = ""
# Number of edges
l = int (math. pow (k, n))
for i in range (l):
S + = A[edges[i]]
S + = startingNode
return S
# Driver code n = 3
k = 2
A = "01"
print (deBruijn(n, k, A))
# This code is contributed by shubhamsingh10 |
// C# implementation of // the above approach using System;
using System.Collections.Generic;
class GFG
{ static HashSet<String> seen = new HashSet<String>();
static List< int > edges = new List< int >();
// Modified DFS in which no edge
// is traversed twice
static void dfs(String node, int k, String A)
{
for ( int i = 0; i < k; ++i)
{
String str = node + A[i];
if (!seen.Contains(str))
{
seen.Add(str);
dfs(str.Substring(1), k, A);
edges.Add(i);
}
}
}
// Function to find a de Bruijn sequence
// of order n on k characters
static String deBruijn( int n, int k, String A)
{
// Clearing global variables
seen.Clear();
edges.Clear();
String startingNode = strings(n - 1, A[0]);
dfs(startingNode, k, A);
String S = "" ;
// Number of edges
int l = ( int ) Math.Pow(k, n);
for ( int i = 0; i < l; ++i)
S += A[edges[i]];
S += startingNode;
return S;
}
private static String strings( int n, char charAt)
{
String str = "" ;
for ( int i = 0; i < n; i++)
str += charAt;
return str;
}
// Driver code
public static void Main(String[] args)
{
int n = 3, k = 2;
String A = "01" ;
Console.Write(deBruijn(n, k, A));
}
} // This code is contributed by 29AjayKumar |
<script> // Javascript implementation of // the above approach var seen = new Set();
var edges = [];
// Modified DFS in which no edge // is traversed twice function dfs(node, k, A)
{ for ( var i = 0; i < k; ++i)
{
var str = node + A[i];
if (!seen.has(str))
{
seen.add(str);
dfs(str.substring(1), k, A);
edges.push(i);
}
}
} // Function to find a de Bruijn sequence // of order n on k characters function deBruijn(n, k, A)
{ // Clearing global variables
seen = new Set();
edges = [];
var startingNode = A[0].repeat(n-1);
dfs(startingNode, k, A);
var S = "" ;
// Number of edges
var l = Math.pow(k, n);
for ( var i = 0; i < l; ++i)
S += A[edges[i]];
S += startingNode;
return S;
} function strings(n, charAt)
{ var str = "" ;
for ( var i = 0; i < n; i++)
str += charAt;
return str;
} // Driver code var n = 3, k = 2;
var A = "01" ;
document.write(deBruijn(n, k, A)); // This code is contributed by rrrtnx. </script> |
0011101000