De Bruijn 序列 |设置 1
给定一个整数n和一组大小为k的字符A ,找到一个字符串S ,使得 A 上所有可能的长度为n的字符串作为S中的子字符串恰好出现一次。这样的字符串称为 de Bruijn 序列。
例子:
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
方法:
我们可以通过构造一个有 k n-1个节点的有向图来解决这个问题,每个节点都有 k 个出边。每个节点对应一个大小为 n-1 的字符串。每条边对应于 A 中的 k 个字符之一,并将该字符添加到起始字符串中。
例如,如果 n=3 且 k=2,那么我们构造如下图:
- 节点'01'通过边'1'连接到节点'11',因为将'1'添加到'01'(并删除第一个字符)给我们'11'。
- 我们可以观察到该图中的每个节点都具有相等的入度和出度,这意味着该图中存在欧拉回路。
- 欧拉回路将对应于 de Bruijn 序列,因为节点和出边的每个组合都表示长度为 n 的唯一字符串。
- de Bruijn 序列将包含起始节点的字符和所有边的字符,按照它们遍历的顺序。
- 因此字符串的长度将是 k n +n-1。我们将使用 Hierholzer 算法找到欧拉回路。这种方法的时间复杂度是 O(k n )。
下面是上述方法的实现:
C++
// C++ implementation of
// the above approach
#include
using namespace std;
unordered_set seen;
vector 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
// Java implementation of
// the above approach
import java.util.*;
class GFG
{
static Set seen = new HashSet();
static Vector edges = new Vector();
// 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
# 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#
// C# implementation of
// the above approach
using System;
using System.Collections.Generic;
class GFG
{
static HashSet seen = new HashSet();
static List edges = new List();
// 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
Javascript
输出:
0011101000