Min Repeats for Substring Match (original) (raw)

Last Updated : 2 Aug, 2025

Given two strings s1 and s2, find the minimum number of times s1 must be repeated so that s2 becomes a substring of the resulting string.
If it is not possible for s2 to be a substring, return -1.

**Examples:

*Input: s1 = "abac", s2 = "cabaca"
Output: 3
Explanation: After repeating s1 three times, s1 will become “abacabacabac”. Now, s2 is now a substring of s1 = "aba
cabaca
*bac". Also s2 is not a substring of s1 when it is repeated less than 3 times.

**Input: s1 = "ab", s2 = "cab"
**Output : -1
**Explanation: s2 can not become a substring of s1 after any repetition of s1.

Try It Yourselfredirect icon

Table of Content

[Naive Approach] Search s2 Over s1 Loop - O(n * m) Time and O(1) Space

The idea is instead of appending string s1 multiple times, we will simply use modulo (i % n) when we reach the end of string s1. Now, iterate over all the characters of s1 and for each character, consider it as the starting point of s2 and start comparing s1 and s2 character by character till we find a mismatch or s2 gets completed. If s2 gets completed, then it means we have found a match and we can simply return the number of times we reached the end of string s1.

C++ `

#include #include using namespace std;

int minRepeats(string &s1, string &s2) { int n = s1.length(), m = s2.length();

// Iterate over all characters of s1 
  // and start comparing with s2
for (int i = 0; i < n; i++) {
    int rep = 1, idx1 = i;
    bool found = true;
  
      // Compare each character of s2 with s1
    for (int idx2 = 0; idx2 < m; idx2++) {
        if (s1[idx1%n] != s2[idx2]) {
            found = false;
            break;
        }
          idx1++;
      
        // If we have reached the end of s1, reset the
        // index to 0
        if (idx1 == n) {
            idx1 = 0;
          
            // If we have remaining character in s2, then
            // s1 needs to repeated again so increment
            // repetitions by 1
            if (idx2 != m - 1)
                rep++;
        }
    }
  
    // If s2 is found, return the number of times 
      // s1 has been repeated
    if (found)
        return rep;
}

  // If no occurrence of s2 is found, return -1
return -1;

}

int main() { string s1 = "abac"; string s2 = "cabaca"; cout << minRepeats(s1, s2); return 0; }

Java

class GfG { static int minRepeats(String s1, String s2) { int n = s1.length(), m = s2.length();

    // Iterate over all characters of s1 
    // and start comparing with s2
    for (int i = 0; i < n; i++) {
        int rep = 1, idx1 = i;
        boolean found = true;

        // Compare each character of s2 with s1
        for (int idx2 = 0; idx2 < m; idx2++) {
            if (s1.charAt(idx1) != s2.charAt(idx2)) {
                found = false;
                break;
            }
            idx1++;

            // If we have reached the end of s1, reset the
            // index to 0
            if (idx1 == n) {
                idx1 = 0;

                // If we have remaining character in s2, then
                // s1 needs to repeated again so increment
                // repetitions by 1
                if (idx2 != m - 1)
                    rep++;
            }
        }

        // If s2 is found, return the number of times 
        // s1 has been repeated
        if (found)
            return rep;
    }

    // If no occurrence of s2 is found, return -1
    return -1;
}

public static void main(String[] args) {
    String s1 = "abac";
    String s2 = "cabaca";
    System.out.println(minRepeats(s1, s2));
}

}

Python

def minRepeats(s1, s2): n, m = len(s1), len(s2)

# Iterate over all characters of s1 
# and start comparing with s2
for i in range(n):
    rep = 1
    idx1 = i
    found = True

    # Compare each character of s2 with s1
    for idx2 in range(m):
        if s1[idx1] != s2[idx2]:
            found = False
            break
        idx1 += 1

        # If we have reached the end of s1, reset the
        # index to 0
        if idx1 == n:
            idx1 = 0

            # If we have remaining character in s2, then
            # s1 needs to repeated again so increment
            # repetitions by 1
            if idx2 != m - 1:
                rep += 1

    # If s2 is found, return the number of times 
    # s1 has been repeated
    if found:
        return rep

# If no occurrence of s2 is found, return -1
return -1

if name == "main": s1 = "abac" s2 = "cabaca" print(minRepeats(s1, s2))

C#

using System;

class GfG {

static int minRepeats(string s1, string s2) {
    int n = s1.Length, m = s2.Length;

    // Iterate over all characters of s1 
    // and start comparing with s2
    for (int i = 0; i < n; i++) {
        int rep = 1, idx1 = i;
        bool found = true;

        // Compare each character of s2 with s1
        for (int idx2 = 0; idx2 < m; idx2++) {
            if (s1[idx1] != s2[idx2]) {
                found = false;
                break;
            }
            idx1++;

            // If we have reached the end of s1, reset the
            // index to 0
            if (idx1 == n) {
                idx1 = 0;

                // If we have remaining character in s2, then
                // s1 needs to repeated again so increment
                // repetitions by 1
                if (idx2 != m - 1)
                    rep++;
            }
        }

        // If s2 is found, return the number of times 
        // s1 has been repeated
        if (found)
            return rep;
    }

    // If no occurrence of s2 is found, return -1
    return -1;
}

static void Main() {
    string s1 = "abac";
    string s2 = "cabaca";
    Console.WriteLine(minRepeats(s1, s2));
}

}

JavaScript

function minRepeats(s1, s2) { let n = s1.length, m = s2.length;

// Iterate over all characters of s1 
// and start comparing with s2
for (let i = 0; i < n; i++) {
    let rep = 1, idx1 = i;
    let found = true;

    // Compare each character of s2 with s1
    for (let idx2 = 0; idx2 < m; idx2++) {
        if (s1[idx1] !== s2[idx2]) {
            found = false;
            break;
        }
        idx1++;

        // If we have reached the end of s1, 
        // reset the index to 0
        if (idx1 === n) {
            idx1 = 0;

            // If we have remaining character in s2, then
            // s1 needs to repeated again so increment
            // repetitions by 1
            if (idx2 !== m - 1)
                rep++;
        }
    }

    // If s2 is found, return the number of times 
    // s1 has been repeated
    if (found)
        return rep;
}

// If no occurrence of s2 is found, return -1
return -1;

}

// Driver code let s1 = "abac"; let s2 = "cabaca"; console.log(minRepeats(s1, s2));

`

[Expected Approach] Using KMP Algorithm - O(n + m) Time and O(m) Space

The idea is to use the KMP (Knuth-Morris-Pratt) pattern matching algorithm to efficiently check if s2 is a substring of repeated s1, without actually constructing the repeated string. Instead of concatenating s1 multiple times, we simulate repetition by cycling through its characters using the modulo operator (%).
We first calculate the minimum number of repetitions x = ceil(len(s2) / len(s1)), and since a potential match could start near the end of one repetition and continue into the next, we also check for x + 1 repetitions. By combining KMP with modulo-based cyclic traversal of s1, we perform the match efficiently in linear time without extra space overhead.

Step by Step Implementation:

#include #include using namespace std;

// function to compute the LPS Array void computeLPSArray(string &s, vector &lps) { int len = 0, idx = 1;

// lps[0] is always 0
lps[0] = 0;

// the loop calculates lps[i] for
// i = 1 to str.length() - 1
while (idx < s.length()) {
    if (s[idx] == s[len]) {
        len++;
        lps[idx] = len;
        idx++;
    }
    else {

        // If len is 0, then we have no common prefix
        // which is also a suffix
        if (len == 0) {
            lps[idx] = 0;
            idx++;
        }
        else {

            // Note that we do not move to the next
            // index
            len = lps[len - 1];
        }
    }
}

}

// function to find the occurrence of pat in txt bool KMPSearch(string &txt, string &pat, vector &lps, int rep) { int n = txt.length(), m = pat.length(); int i = 0, j = 0;

// Iterate till s1 is repeated rep times
while (i < n * rep) {

    // If characters match, move both pointers forward
    if (txt[i % n] == pat[j]) {
        i++;
        j++;

        // If the entire pattern is matched
        // store the start index in result
        if (j == m) {
            return true;
        }
    }

    // If there is a mismatch
    else {

        // Use lps value of previous index
        // to avoid redundant comparisons
        if (j != 0)
            j = lps[j - 1];
        else
            i++;
    }
}
return false;

}

// function to find Minimum number of times s1 has to be // repeated such that s2 is a substring of it int minRepeats(string &s1, string &s2) {

int n = s1.length();
int m = s2.length();

// Declare and Compute the LPS Table
vector<int> lps(m);
computeLPSArray(s2, lps);

// Find the minimum nnumber of times s1 needs to be
// repeated to become as long as s2
int x = (m + n - 1) / n;

// Check when string s1 is repeated x times
if (KMPSearch(s1, s2, lps, x))
    return x;

// Check when string s1 is repeated (x + 1) times
if (KMPSearch(s1, s2, lps, x + 1))
    return x + 1;

// If string s2 was not found, return -1
return -1;

}

int main() { string s1 = "abac"; string s2 = "cabaca"; cout << minRepeats(s1, s2); return 0; }

C

#include <stdio.h> #include <string.h> #include <stdbool.h>

// function to compute the LPS Array void computeLPSArray(char *s, int *lps, int len) { int length = 0, idx = 1;

// lps[0] is always 0
lps[0] = 0;

// the loop calculates lps[i] for
// i = 1 to str.length() - 1
while (idx < len) {
    if (s[idx] == s[length]) {
        length++;
        lps[idx] = length;
        idx++;
    } 
    else {
      
        // If length is 0, then we have no common prefix
        // which is also a suffix
        if (length == 0) {
            lps[idx] = 0;
            idx++;
        } 
        else {
          
            // Note that we do not move to the next index
            length = lps[length - 1];
        }
    }
}

}

// function to find the occurrence of pat in txt bool KMPSearch(char *txt, char *pat, int *lps, int rep, int n) { int m = strlen(pat); int i = 0, j = 0;

// Iterate till s1 is repeated rep times
while (i < n * rep) {
    // If characters match, move both pointers forward
    if (txt[i % n] == pat[j]) {
        i++;
        j++;

        // If the entire pattern is matched
        if (j == m) {
            return true;
        }
    } 
    else {
      
        // If there is a mismatch use lps value of previous 
        // index to avoid redundant comparisons
        if (j != 0)
            j = lps[j - 1];
        else
            i++;
    }
}
return false;

}

// function to find Minimum number of times s1 has to be // repeated such that s2 is a substring of it int minRepeats(char *s1, char *s2) {

int n = strlen(s1);
int m = strlen(s2);

// Compute the LPS Array
int lps[m];
computeLPSArray(s2, lps, m);

// Find the minimum number of times s1 needs to be
// repeated to become as long as s2
int x = (m + n - 1) / n;

// Check when string s1 is repeated x times
if (KMPSearch(s1, s2, lps, x, n))
    return x;

// Check when string s1 is repeated (x + 1) times
if (KMPSearch(s1, s2, lps, x + 1, n))
    return x + 1;

// If string s2 was not found, return -1
return -1;

}

int main() { char s1[] = "abac"; char s2[] = "cabaca"; printf("%d\n", minRepeats(s1, s2)); return 0; }

Java

class GfG {

// function to compute the LPS Array
static void computeLPSArray(String s, int[] lps) {
    int len = 0, idx = 1;

    // lps[0] is always 0
    lps[0] = 0;

    // the loop calculates lps[i] for
    // i = 1 to str.length() - 1
    while (idx < s.length()) {
        if (s.charAt(idx) == s.charAt(len)) {
            len++;
            lps[idx] = len;
            idx++;
        } 
        else {
            
            // If len is 0, then we have no common prefix
            // which is also a suffix
            if (len == 0) {
                lps[idx] = 0;
                idx++;
            } 
            else {
              
                // Note that we do not move to the next index
                len = lps[len - 1];
            }
        }
    }
}

// function to find the occurrence of pat in txt
static boolean KMPSearch(String txt, String pat, int[] lps, int rep) {
    int n = txt.length(), m = pat.length();
    int i = 0, j = 0;

    // Iterate till s1 is repeated rep times
    while (i < n * rep) {
        
        // If characters match, move both pointers forward
        if (txt.charAt(i % n) == pat.charAt(j)) {
            i++;
            j++;

            // If the entire pattern is matched
            if (j == m) {
                return true;
            }
        } 
        else {
            
            // If there is a mismatch
            // Use lps value of previous index to avoid redundant comparisons
            if (j != 0)
                j = lps[j - 1];
            else
                i++;
        }
    }
    return false;
}

// function to find Minimum number of times s1 has to be
// repeated such that s2 is a substring of it
static int minRepeats(String s1, String s2) {

    int n = s1.length();
    int m = s2.length();

    // Declare and Compute the LPS Table
    int[] lps = new int[m];
    computeLPSArray(s2, lps);

    // Find the minimum number of times s1 needs to be
    // repeated to become as long as s2
    int x = (m + n - 1) / n;

    // Check when string s1 is repeated x times
    if (KMPSearch(s1, s2, lps, x))
        return x;

    // Check when string s1 is repeated (x + 1) times
    if (KMPSearch(s1, s2, lps, x + 1))
        return x + 1;

    // If string s2 was not found, return -1
    return -1;
}

public static void main(String[] args) {
    String s1 = "abac";
    String s2 = "cabaca";
    System.out.println(minRepeats(s1, s2));
}

}

Python

def computeLPSArray(s): lps = [0] * len(s) len_ = 0 idx = 1

# the loop calculates lps[i] for
# i = 1 to str.length() - 1
while idx < len(s):
    if s[idx] == s[len_]:
        len_ += 1
        lps[idx] = len_
        idx += 1
    else:
        
        # If len is 0, then we have no common prefix
        # which is also a suffix
        if len_ == 0:
            lps[idx] = 0
            idx += 1
        else:
            
            # Note that we do not move to the next index
            len_ = lps[len_ - 1]
return lps

function to find the occurrence of pat in txt

def KMPSearch(txt, pat, lps): n, m = len(txt), len(pat) i = j = 0

# Iterate till s1 is repeated rep times
while i < n:
    
    # If characters match, move both pointers forward
    if txt[i] == pat[j]:
        i += 1
        j += 1

        # If the entire pattern is matched
        if j == m:
            return True
            
            # Use lps of previous index to skip 
            # unnecessary comparisons
            j = lps[j - 1]
    else:
        
        # If there is a mismatch, use lps value of 
        # previous index to avoid redundant comparisons
        if j != 0:
            j = lps[j - 1]
        else:
            i += 1
return False

function to find Minimum number of times s1 has to be

repeated such that s2 is a substring of it

def minRepeats(s1, s2):

n, m = len(s1), len(s2)

# Declare and Compute the LPS Table
lps = computeLPSArray(s2)

# Find the minimum number of times s1 needs to be
# repeated to become as long as s2
x = (m + n - 1) // n

text = s1 * x

# Check when string s1 is repeated x times
if KMPSearch(text, s2, lps):
    return x

text += s1
  
# Check when string s1 is repeated (x + 1) times
if KMPSearch(text, s2, lps):
    return x + 1

# If string s2 was not found, return -1
return -1

if name == 'main': s1 = "abac" s2 = "cabaca" print(minRepeats(s1, s2))

C#

using System; using System.Collections.Generic;

class GfG {

// function to compute the LPS Array
static void computeLPSArray(string s, int[] lps) {
    int len = 0, idx = 1;

    // lps[0] is always 0
    lps[0] = 0;

    // the loop calculates lps[i] for
    // i = 1 to str.length() - 1
    while (idx < s.Length) {
        if (s[idx] == s[len]) {
            len++;
            lps[idx] = len;
            idx++;
        } 
        else {
          
            // If len is 0, then we have no common prefix
            // which is also a suffix
            if (len == 0) {
                lps[idx] = 0;
                idx++;
            } 
            else {
              
                // Note that we do not move to the next
                // index
                len = lps[len - 1];
            }
        }
    }
}

// function to find the occurrence of pat in txt
static bool KMPSearch(string txt, string pat, int[] lps, int rep) {
    int n = txt.Length, m = pat.Length;
    int i = 0, j = 0;

    // Iterate till s1 is repeated rep times
    while (i < n * rep) {
      
        // If characters match, move both pointers forward
        if (txt[i % n] == pat[j]) {
            i++;
            j++;

            // If the entire pattern is matched
            // store the start index in result
            if (j == m) {
                return true;
            }
        } 
        else {
          
            // If there is a mismatch use lps value of 
            // previous index to avoid redundant comparisons
            if (j != 0)
                j = lps[j - 1];
            else
                i++;
        }
    }
    return false;
}

// function to find Minimum number of times s1 has to be
// repeated such that s2 is a substring of it
static int minRepeats(string s1, string s2) {
    
    int n = s1.Length;
    int m = s2.Length;

    // Declare and Compute the LPS Table
    int[] lps = new int[m];
    computeLPSArray(s2, lps);

    // Find the minimum number of times s1 needs to be
    // repeated to become as long as s2
    int x = (m + n - 1) / n;

    // Check when string s1 is repeated x times
    if (KMPSearch(s1, s2, lps, x))
        return x;

    // Check when string s1 is repeated (x + 1) times
    if (KMPSearch(s1, s2, lps, x + 1))
        return x + 1;

    // If string s2 was not found, return -1
    return -1;
}

static void Main() {
    string s1 = "abac";
    string s2 = "cabaca";

    Console.WriteLine(minRepeats(s1, s2));
}

}

JavaScript

function computeLPSArray(s) { let len = 0; const lps = new Array(s.length).fill(0); let idx = 1;

// lps[0] is always 0
while (idx < s.length) {
    if (s[idx] === s[len]) {
        len++;
        lps[idx] = len;
        idx++;
    } 
    else {
        
        // If len is 0, then we have no common prefix
        // which is also a suffix
        if (len === 0) {
            lps[idx] = 0;
            idx++;
        } 
        else {
            
            // Note that we do not move to the next
            // index
            len = lps[len - 1];
        }
    }
}
return lps;

}

// function to find the occurrence of pat in txt function KMPSearch(txt, pat, lps, rep) { const n = txt.length; const m = pat.length; let i = 0, j = 0;

// Iterate till s1 is repeated rep times
while (i < n * rep) {
    
    // If characters match, move both pointers forward
    if (txt[i % n] === pat[j]) {
        i++;
        j++;

        // If the entire pattern is matched
        // store the start index in result
        if (j === m) {
            return true;
        }
    } 
    else {
        
        // If there is a mismatch use lps value of 
        // previous index to avoid redundant comparisons
        if (j !== 0)
            j = lps[j - 1];
        else
            i++;
    }
}
return false;

}

// function to find Minimum number of times s1 has to be // repeated such that s2 is a substring of it function minRepeats(s1, s2) {

const n = s1.length;
const m = s2.length;

// Declare and Compute the LPS Table
const lps = computeLPSArray(s2);

// Find the minimum number of times s1 needs to be
// repeated to become as long as s2
const x = Math.ceil(m / n);

// Check when string s1 is repeated x times
if (KMPSearch(s1, s2, lps, x))
    return x;

// Check when string s1 is repeated (x + 1) times
if (KMPSearch(s1, s2, lps, x + 1))
    return x + 1;

// If string s2 was not found, return -1
return -1;

}

// Driver Code const s1 = "abac"; const s2 = "cabaca"; console.log(minRepeats(s1, s2));

`