Open In App

Minimum Repetitions of s1 such that s2 is a substring of it

Last Updated : 29 Nov, 2024
Summarize
Comments
Improve
Suggest changes
Like Article
Like
Save
Share
Report
News Follow

Given two strings s1 and s2, the task is to find the minimum number of times s1 has to be repeated such that s2 is a substring of it. If no such solution exists, print -1.

Examples: 

Input: s1 = “abcd”, s2 = “cdabcdab”
Output:
Explanation: After repeating s1 three times, s1 will become “abcdabcdabcd”. Now, s2 is now a substring of s1 = “abcdabcdabcd”. 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.

[Naive Approach] Matching characters of s2 with repeated occurrence of s1 – 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++
// C++ Program to find Minimum number of times s1 has 
// to be repeated such that s2 is a substring of it

#include <iostream>
#include <vector>
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] != 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 = "abcd";
      string s2 = "cdabcdab";
      
    cout << minRepeats(s1, s2);
    return 0;
}
Java
// Java program to find Minimum number of times s1 has to be
// repeated such that s2 is a substring of it

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 = "abcd";
        String s2 = "cdabcdab";

        System.out.println(minRepeats(s1, s2));
    }
}
Python
# Python program 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)

    # 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 = "abcd"
    s2 = "cdabcdab"

    print(minRepeats(s1, s2))
C#
// C# program to find Minimum number of times s1 has to be
// repeated such that s2 is a substring of it

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 = "abcd";
        string s2 = "cdabcdab";

        Console.WriteLine(minRepeats(s1, s2));
    }
}
JavaScript
// JavaScript program to find Minimum number of times s1 has to be
// repeated such that s2 is a substring of it

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 = "abcd";
let s2 = "cdabcdab";

console.log(minRepeats(s1, s2));

Output
3

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

In order to have s2 as a substring of s1, s1 should be at least as long as s2. Assume x to be the minimum number of times s1 needs to be repeated such that its length becomes greater than or equal to s2. So, x = ceil( len(s2) / len(s1) ).

If we observe carefully, the minimum number of times s1 needs to be repeated such that s2 is a substring of it will always be either x or x + 1. This is because the substring in s1 that is equal to s2 after repeating s1 certain number of times, must start at index: 0, 1, 2, 3 … len(s1) – 1. As anything after len(s1) – 1 will be same as these starting indices. Therefore, we need to make sure that starting from any of these indices: 0, 1, 2, 3 … len(s1) – 1, the new repeated string s1 must be long enough to have s2 as a substring. Even, if we start from index len(s1) – 1, we need the new string s1 to be long enough to have all characters of s2. This cannot be ensured by repeating x number of times. However, if we repeat (x + 1) times then we can ensure that whatever be the starting index of the substring which is equal to s2, the new string s1 will always be long enough to have all the characters of s2.

Now, instead of constructing a new string by appending s1 multiple times, we can simply use modulo operator to traverse s1 in a cyclic manner and then use KMP Algorithm to find s2 as a substring of s1.

C++
// C++ program to find Minimum number of times s1
// has to be repeated such that s2 is a substring of it
// using KMP algorithm

#include <iostream>
#include <vector>
using namespace std;

// function to compute the LPS Array
void computeLPSArray(string &s, vector<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
bool KMPSearch(string &txt, string &pat, vector<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;
            }
        }

        // 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) {

    // Find lengths of strings
    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 = "abcd";
    string s2 = "cdabcdab";

    cout << minRepeats(s1, s2);
    return 0;
}
C
// C program to find Minimum number of times s1
// has to be repeated such that s2 is a substring of it
// using KMP algorithm

#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[] = "abcd";
    char s2[] = "cdabcdab";

    printf("%d\n", minRepeats(s1, s2));
    return 0;
}
Java
// Java program to find Minimum number of times s1
// has to be repeated such that s2 is a substring of it
// using KMP algorithm

import java.util.*;

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) {
        
        // Find lengths of strings
        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 = "abcd";
        String s2 = "cdabcdab";

        System.out.println(minRepeats(s1, s2));
    }
}
Python
# Python program to find Minimum number of times s1
# has to be repeated such that s2 is a substring of it
# using KMP algorithm

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):
    
    # Find lengths of strings
    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 = "abcd"
    s2 = "cdabcdab"

    print(minRepeats(s1, s2))
C#
// C# program to find Minimum number of times s1
// has to be repeated such that s2 is a substring of it
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) {
        
        // Find lengths of strings
        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 = "abcd";
        string s2 = "cdabcdab";

        Console.WriteLine(minRepeats(s1, s2));
    }
}
JavaScript
// JavaScript program to find Minimum number of times s1
// has to be repeated such that s2 is a substring of it

// function to compute the LPS Array
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) {
    
    // Find lengths of strings
    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;
}

const s1 = "abcd";
const s2 = "cdabcdab";
console.log(minRepeats(s1, s2));

Output
3




Next Article

Similar Reads

three90RightbarBannerImg