Given a string s, the task is to check if it can be constructed by taking a substring of it and appending multiple copies of the substring together.
Examples:
Input: s = "abcabcabc"
Output: true
Explanation: The given string is 3 times repetition of "abc"Input: s = "abadabad"
Output: true
Explanation: The given string is 2 times repetition of "abad"Input: s = "aabaabaabaab"
Output: true
Explanation: The given string is 4 times repetition of "aab"
Source: Google Interview Question
Table of Content
[Naive Approach] Using Substring Repetition Check – O(n²) Time and O(n) Space
The idea is to try every possible substring length that can divide the original string length. For each valid length, we extract the substring and repeatedly concatenate it to form a new string. If the newly formed string becomes equal to the original string, then the given string is made by repeating that substring.
- Try all substring lengths from
1ton/2 - Consider only lengths that exactly divide the string length
- Extract the substring and repeat it required number of times
- Compare the generated string with the original string and return result
#include <iostream>
#include <string>
using namespace std;
bool isRepeat(string &s)
{
int n = s.size();
// try every possible substring length
for(int len = 1; len <= n/2; len++)
{
// substring length must divide n
if(n % len == 0)
{
string part = s.substr(0, len);
string temp = "";
int times = n / len;
// repeat substring
for(int i = 0; i < times; i++)
{
temp += part;
}
// check if formed string equals original
if(temp == s)
{
return true;
}
}
}
return false;
}
int main()
{
string s = "abcabcabc";
if(isRepeat(s))
cout << "True";
else
cout << "False";
return 0;
}
import java.util.*;
class GFG {
static boolean isRepeat(String s)
{
int n = s.length();
// try every possible substring length
for(int len = 1; len <= n / 2; len++)
{
// substring length must divide n
if(n % len == 0)
{
String part = s.substring(0, len);
String temp = "";
int times = n / len;
// repeat substring
for(int i = 0; i < times; i++)
{
temp += part;
}
// check if formed string equals original
if(temp.equals(s))
{
return true;
}
}
}
return false;
}
public static void main(String[] args)
{
String s = "abcabcabc";
if(isRepeat(s))
System.out.println("True");
else
System.out.println("False");
}
}
def isRepeat(s):
n = len(s)
# try every possible substring length
for length in range(1, n // 2 + 1):
# substring length must divide n
if n % length == 0:
part = s[0:length]
temp = ""
times = n // length
# repeat substring
for i in range(times):
temp += part
# check if formed string equals original
if temp == s:
return True
return False
s = "abcabcabc"
if isRepeat(s):
print("True")
else:
print("False")
using System;
class GFG {
static bool isRepeat(string s)
{
int n = s.Length;
// try every possible substring length
for(int len = 1; len <= n / 2; len++)
{
// substring length must divide n
if(n % len == 0)
{
string part = s.Substring(0, len);
string temp = "";
int times = n / len;
// repeat substring
for(int i = 0; i < times; i++)
{
temp += part;
}
// check if formed string equals original
if(temp == s)
{
return true;
}
}
}
return false;
}
static void Main()
{
string s = "abcabcabc";
if(isRepeat(s))
Console.WriteLine("True");
else
Console.WriteLine("False");
}
}
function isRepeat(s)
{
let n = s.length;
// try every possible substring length
for(let len = 1; len <= Math.floor(n / 2); len++)
{
// substring length must divide n
if(n % len == 0)
{
let part = s.substring(0, len);
let temp = "";
let times = Math.floor(n / len);
// repeat substring
for(let i = 0; i < times; i++)
{
temp += part;
}
// check if formed string equals original
if(temp == s)
{
return true;
}
}
}
return false;
}
let s = "abcabcabc";
if(isRepeat(s))
console.log("True");
else
console.log("False");
Output
True
[Efficient Approach] Using KMP (LPS Array) – O(n) Time and O(n) Space
The idea is to use the Longest Prefix Suffix (LPS) array from the KMP algorithm. If a string is formed by repeating one of its substrings, then the string will have a proper prefix that is also a suffix. The last value of the LPS array gives the length of this repeating pattern. Using this value, we check whether the remaining substring length divides the total string length completely.
- Construct the LPS array for the given string using KMP preprocessing
- Find the length of the longest proper prefix which is also a suffix
- Compute the repeating substring length using
n - lps[n-1] - If the string length is divisible by this value, return true otherwise false
Why does this work?
Let us consider the two cases.
- String is actually a repetition : Then a large part of the prefix appears again at the end therefore LPS of last character becomes large. If there are exactly two repetitions, then there would not be any overlapping in prefix and suffix. Otherwise there would be an overlapping part in the common part of suffix and prefix. In both the cases, we get length of the repeating substring by subtracting LPS of last from total length.
- String is not a repetition : There are two cases here. If the LPS of last character is 0, then string is definitely not a repitiion. If LPS is not 0, for example, bbxxbb has LPS 2. In this case there is no common part which we check by checking divisibility of total length - LPS with the total length.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// A utility function to fill lps[] or compute prefix
// function used in KMP string matching algorithm.
void computeLPSArray(string &s, int n, vector<int>& lps)
{
// length of the previous longest prefix suffix
int len = 0;
int i;
lps[0] = 0; // lps[0] is always 0
i = 1;
// the loop calculates lps[i] for i = 1 to n-1
while (i < n) {
if (s[i] == s[len]) {
len++;
lps[i] = len;
i++;
}
else // (s[i] != s[len])
{
if (len != 0) {
// This is tricky. Consider the example
// AAACAAAA and i = 7.
len = lps[len - 1];
// Also, note that we do not increment i
// here
}
else // if (len == 0)
{
lps[i] = 0;
i++;
}
}
}
}
// Returns true if s is repetition of one of its
// substrings else return false.
bool isRepeat(string &s)
{
// Find length of string and create an array to
// store lps values used in KMP
int n = s.length();
vector<int> lps(n);
// Preprocess the pattern (calculate lps[] array)
computeLPSArray(s, n, lps);
// Find length of longest suffix which is also
// prefix of s.
int len = lps[n - 1];
// If there exist a suffix which is also prefix AND
// Length of the remaining substring divides total
// length, then s[0..n-len-1] is the substring that
// repeats n/(n-len) times
return (len > 0 && n % (n - len) == 0) ? true : false;
}
// Driver program to test above function
int main()
{
string s = "ABCABC";
isRepeat(s) ? cout << "True"
: cout << "False";
return 0;
}
import java.util.*;
class GFG {
// A utility function to fill lps[] or compute prefix
// function used in KMP string matching algorithm.
static void computeLPSArray(String s, int n, int[] lps)
{
// length of the previous longest prefix suffix
int len = 0;
int i;
lps[0] = 0; // lps[0] is always 0
i = 1;
// the loop calculates lps[i] for i = 1 to n-1
while (i < n) {
if (s.charAt(i) == s.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else // (s[i] != s[len])
{
if (len != 0) {
// This is tricky. Consider the example
// AAACAAAA and i = 7.
len = lps[len - 1];
// Also, note that we do not increment i
// here
}
else // if (len == 0)
{
lps[i] = 0;
i++;
}
}
}
}
// Returns true if s is repetition of one of its
// substrings else return false.
static boolean isRepeat(String s)
{
// Find length of string and create an array to
// store lps values used in KMP
int n = s.length();
int[] lps = new int[n];
// Preprocess the pattern (calculate lps[] array)
computeLPSArray(s, n, lps);
// Find length of longest suffix which is also
// prefix of s.
int len = lps[n - 1];
// If there exist a suffix which is also prefix AND
// Length of the remaining substring divides total
// length, then s[0..n-len-1] is the substring that
// repeats n/(n-len) times
return (len > 0 && n % (n - len) == 0) ? true : false;
}
// Driver program to test above function
public static void main(String[] args)
{
String s = "ABCABC";
System.out.println(isRepeat(s) ? "True"
: "False");
}
}
// This code is contributed by Aditya Kumar (adityakumar129)
# A utility function to fill lps[] or compute prefix
# function used in KMP string matching algorithm.
def computeLPSArray(s, n, lps):
# length of the previous longest prefix suffix
length = 0
lps[0] = 0 # lps[0] is always 0
i = 1
# the loop calculates lps[i] for i = 1 to n-1
while i < n:
if s[i] == s[length]:
length += 1
lps[i] = length
i += 1
else: # (s[i] != s[len])
if length != 0:
# This is tricky. Consider the example
# AAACAAAA and i = 7.
length = lps[length - 1]
# Also, note that we do not increment i
# here
else: # if (len == 0)
lps[i] = 0
i += 1
# Returns true if s is repetition of one of its
# substrings else return false.
def isRepeat(s):
# Find length of string and create an array to
# store lps values used in KMP
n = len(s)
lps = [0] * n
# Preprocess the pattern (calculate lps[] array)
computeLPSArray(s, n, lps)
# Find length of longest suffix which is also
# prefix of s.
length = lps[n - 1]
# If there exist a suffix which is also prefix AND
# Length of the remaining substring divides total
# length, then s[0..n-len-1] is the substring that
# repeats n/(n-len) times
return True if (length > 0 and
n % (n - length) == 0) else False
# Driver program to test above function
s = "ABCABC"
print("True" if isRepeat(s)
else "False")
using System;
class GFG {
// A utility function to fill lps[] or compute prefix
// function used in KMP string matching algorithm.
static void computeLPSArray(string s, int n, int[] lps)
{
// length of the previous longest prefix suffix
int len = 0;
int i;
lps[0] = 0; // lps[0] is always 0
i = 1;
// the loop calculates lps[i] for i = 1 to n-1
while (i < n) {
if (s[i] == s[len]) {
len++;
lps[i] = len;
i++;
}
else // (s[i] != s[len])
{
if (len != 0) {
// This is tricky. Consider the example
// AAACAAAA and i = 7.
len = lps[len - 1];
// Also, note that we do not increment i
// here
}
else // if (len == 0)
{
lps[i] = 0;
i++;
}
}
}
}
// Returns true if s is repetition of one of its
// substrings else return false.
static bool isRepeat(string s)
{
// Find length of string and create an array to
// store lps values used in KMP
int n = s.Length;
int[] lps = new int[n];
// Preprocess the pattern (calculate lps[] array)
computeLPSArray(s, n, lps);
// Find length of longest suffix which is also
// prefix of s.
int len = lps[n - 1];
// If there exist a suffix which is also prefix AND
// Length of the remaining substring divides total
// length, then s[0..n-len-1] is the substring that
// repeats n/(n-len) times
return (len > 0 && n % (n - len) == 0) ? true : false;
}
// Driver program to test above function
static void Main()
{
string s = "ABCABC";
Console.WriteLine(isRepeat(s) ? "True"
: "False");
}
}
// A utility function to fill lps[] or compute prefix
// function used in KMP string matching algorithm.
function computeLPSArray(s, n, lps)
{
// length of the previous longest prefix suffix
let len = 0;
lps[0] = 0; // lps[0] is always 0
let i = 1;
// the loop calculates lps[i] for i = 1 to n-1
while (i < n) {
if (s[i] == s[len]) {
len++;
lps[i] = len;
i++;
}
else // (s[i] != s[len])
{
if (len != 0) {
// This is tricky. Consider the example
// AAACAAAA and i = 7.
len = lps[len - 1];
// Also, note that we do not increment i
// here
}
else // if (len == 0)
{
lps[i] = 0;
i++;
}
}
}
}
// Returns true if s is repetition of one of its
// substrings else return false.
function isRepeat(s)
{
// Find length of string and create an array to
// store lps values used in KMP
let n = s.length;
let lps = new Array(n).fill(0);
// Preprocess the pattern (calculate lps[] array)
computeLPSArray(s, n, lps);
// Find length of longest suffix which is also
// prefix of s.
let len = lps[n - 1];
// If there exist a suffix which is also prefix AND
// Length of the remaining substring divides total
// length, then s[0..n-len-1] is the substring that
// repeats n/(n-len) times
return (len > 0 && n % (n - len) == 0) ? true : false;
}
// Driver program to test above function
let s = "ABCABC";
console.log(isRepeat(s) ? "True"
: "False");
Output
True