Open In App

Min Length String with All Substrings of Size N

Last Updated : 28 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

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.
C++
// 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;
}
Java
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);
    }
}
Python
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)
C#
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);
    }
}
JavaScript
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.


Next Article

Similar Reads