Given two integers n and k, your task is to find a string of minimum length to contain all possible strings of size n as a substring. The characters of the string should be integers ranging from 0 to k - 1.
Examples:
Input: n = 2, k = 2
Output: 00110
Explanation: Allowed characters are from 0 to k-1 (i.e., 0 and 1). There are 4 string possible of size n = 2 and two integers (i.e "00", "01","10","11"). "00110" contains all possible string as a substring.Input: n = 2, k = 3
Output: 0022120110
Explanation: Allowed characters are from 0 to k-1 (i.e., 0, 1 and 2). There are total 9 strings possible of size N, given output string has the minimum length that contains all those strings as substring.
Approach:
The idea is to construct a De Bruijn–style sequence by starting with N zeros and then, at each step, appending the biggest possible digit that creates a new length-n substring. By always choosing the extension that hasn’t been seen before, the algorithm guarantees that every n-digit string over {0,…,K−1} will appear exactly once in the shortest possible superstring.
Why does this work?
- We start with a string of size
n, and every appended character creates a new substring. We use a hashset to ensure that we append only when a new substring is being generated. - Therefore, the total string length will be: k^n + (n-1) which is the minimum possible length.
Step by Step Algorithm
- Initialize an empty string ans with n zeros
- Decrement K by 1 to convert to 0-based digits
- Create an unordered set visited and insert the initial string res.
- Loop until visited.size() equals (K+1) ^ n. Inside the loop, start with largest digit and stop when we find a digit such that appending the digit covers a new substring.
// CPP program for the above approach
#include <bits/stdc++.h>
using namespace std;
// Function to find a string of minimum length to
// contain all possible strings of size n as a substring
string findString(int n, int k) {
// Initialize the result string with n '0'
string res;
for (int i = 0; i < n; i++)
res += "0";
// Decrement k for 0-based indexing
k -= 1;
// Set to store visited strings
unordered_set<string> visited;
visited.insert(res);
// Loop until all possible strings are generated
while (visited.size() < pow((k + 1), n)) {
// Get the substring for the previous n-1
// characters
string previous = res.substr(res.length() - n + 1);
// Iterate from k to 0 to find the
// next character to append
for (int i = k; i >= 0; i--) {
string currStr = previous + to_string(i);
// If the current string is not visited,
// insert it and append to the result
if (visited.find(currStr) == visited.end()) {
visited.insert(currStr);
res += to_string(i);
break;
}
}
}
return res;
}
int main() {
int n = 2;
int k = 3;
string res = findString(n, k);
cout << res;
return 0;
}
import java.util.*;
public class GfG {
public static String findString(int n, int k) {
// Function to find a string of minimum length to
// contain all possible strings of size n as a substring
// Initialize the result string with n '0'
String res = "";
for (int i = 0; i < n; i++)
res += "0";
// Decrement k for 0-based indexing
k -= 1;
// Set to store visited strings
Set<String> visited = new HashSet<>();
visited.add(res);
// Loop until all possible strings are generated
while (visited.size() < Math.pow((k + 1), n)) {
// Get the substring for the previous n-1
// characters
String previous = res.substring(res.length() - n + 1);
// Iterate from k to 0 to find the
// next character to append
for (int i = k; i >= 0; i--) {
String currStr = previous + Integer.toString(i);
// If the current string is not visited,
// insert it and append to the result
if (!visited.contains(currStr)) {
visited.add(currStr);
res += Integer.toString(i);
break;
}
}
}
return res;
}
public static void main(String[] args) {
int n = 2;
int k = 3;
String res = findString(n, k);
System.out.println(res);
}
}
def findString(n, k):
# Function to find a string of minimum length to
# contain all possible strings of size n as a substring
# Initialize the result string with n '0'
res = ""
for i in range(n):
res += "0"
# Decrement k for 0-based indexing
k -= 1
# Set to store visited strings
visited = set()
visited.add(res)
# Loop until all possible strings are generated
while len(visited) < pow((k + 1), n):
# Get the substring for the previous n-1
# characters
previous = res[len(res) - n + 1:]
# Iterate from k to 0 to find the
# next character to append
for i in range(k, -1, -1):
currStr = previous + str(i)
# If the current string is not visited,
# insert it and append to the result
if currStr not in visited:
visited.add(currStr)
res += str(i)
break
return res
if __name__ == "__main__":
n = 2
k = 3
res = findString(n, k)
print(res)
using System;
using System.Collections.Generic;
public class GfG {
public static string findString(int n, int k) {
// Function to find a string of minimum length to
// contain all possible strings of size n as a substring
// Initialize the result string with n '0'
string res = "";
for (int i = 0; i < n; i++)
res += "0";
// Decrement k for 0-based indexing
k -= 1;
// Set to store visited strings
HashSet<string> visited = new HashSet<string>();
visited.Add(res);
// Loop until all possible strings are generated
while (visited.Count < Math.Pow((k + 1), n)) {
// Get the substring for the previous n-1
// characters
string previous = res.Substring(res.Length - n + 1);
// Iterate from k to 0 to find the
// next character to append
for (int i = k; i >= 0; i--) {
string currStr = previous + i.ToString();
// If the current string is not visited,
// insert it and append to the result
if (!visited.Contains(currStr)) {
visited.Add(currStr);
res += i.ToString();
break;
}
}
}
return res;
}
public static void Main() {
int n = 2;
int k = 3;
string res = findString(n, k);
Console.WriteLine(res);
}
}
function findString(n, k) {
// Function to find a string of minimum length to
// contain all possible strings of size n as a substring
// Initialize the result string with n '0'
let res = "";
for (let i = 0; i < n; i++)
res += "0";
// Decrement k for 0-based indexing
k -= 1;
// Set to store visited strings
const visited = new Set();
visited.add(res);
// Loop until all possible strings are generated
while (visited.size < Math.pow((k + 1), n)) {
// Get the substring for the previous n-1
// characters
const previous = res.substring(res.length - n + 1);
// Iterate from k to 0 to find the
// next character to append
for (let i = k; i >= 0; i--) {
const currStr = previous + i.toString();
// If the current string is not visited,
// insert it and append to the result
if (!visited.has(currStr)) {
visited.add(currStr);
res += i.toString();
break;
}
}
}
return res;
}
const n = 2;
const k = 3;
const res = findString(n, k);
console.log(res);
Output
0022120110
Time Complexity: O(kn + 1), As we are running the loop of size O(kn + 1).
Auxiliary Space: O(kn + 1), As we have the set to store the all the possible permutations.