Find if a given string can be represented from a substring by iterating the substring “n” times
Given a string ‘str’, check if it can be constructed by taking a substring of it and appending multiple copies of the substring together.
Examples:
Input: str = "abcabcabc"
Output: true
The given string is 3 times repetition of "abc"
Input: str = "abadabad"
Output: true
The given string is 2 times repetition of "abad"
Input: str = "aabaabaabaab"
Output: true
The given string is 4 times repetition of "aab"
Input: str = "abcdabc"
Output: false
Source: Google Interview Question
There can be many solutions to this problem. The challenging part is to solve the problem in O(n) time. Below is a O(n) algorithm.
Let the given string be ‘str’ and length of given string be ‘n’.
- Find the length of the longest proper prefix of ‘str’ which is also a suffix. Let the length of the longest proper prefix suffix be ‘len’. This can be computed in O(n) time using pre-processing step of KMP string matching algorithm.
- If value of ‘n – len’ divides n (or ‘n % (n-len)’ is 0), then return true, else return false.
In case of ‘true’ , the substring ‘str[0..n-len-1]’ is the substring that repeats n/(n-len) times.
Let us take few examples. Input: str = “ABCDABCD”, n = 8 (Number of characters in ‘str’) The value of len is 4 (“ABCD” is the longest substring which is both prefix and suffix) Since (n-len) divides n, the answer is true. Input: str = “ABCDABC”, n = 7 (Number of characters in ‘str’) The value of len is 3 (“ABC” is the longest substring which is both prefix and suffix) Since (n-len) doesn’t divides n, the answer is false. Input: str = “ABCABCABCABCABC”, n = 15 (Number of characters in ‘str’) The value of len is 12 (“ABCABCABCABC” is the longest substring which is both prefix and suffix) Since (n-len) divides n, the answer is true.
How does this work?
length of longest proper prefix-suffix (or len) is always between 0 to n-1. If len is n-1, then all characters in string are same. For example len is 3 for “AAAA”. If len is n-2 and n is even, then two characters in string repeat n/2 times. For example “ABABABAB”, length of lps is 6. The reason is if the first n-2 characters are same as last n-2 character, the starting from the first pair, every pair of characters is identical to the next pair. The following diagram demonstrates same for substring of length 4.
Following is the implementation of above algorithm:
C++
#include <bits/stdc++.h>
using namespace std;
void computeLPSArray( char str[], int M, int lps[])
{
int len = 0;
int i;
lps[0] = 0;
i = 1;
while (i < M) {
if (str[i] == str[len]) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1];
}
else
{
lps[i] = 0;
i++;
}
}
}
}
bool isRepeat( char str[])
{
int n = strlen (str);
int lps[n];
computeLPSArray(str, n, lps);
int len = lps[n - 1];
return (len > 0 && n % (n - len) == 0) ? true : false ;
}
int main()
{
char txt[][100]
= { "ABCABC" , "ABABAB" , "ABCDABCD" ,
"GEEKSFORGEEKS" , "GEEKGEEK" , "AAAACAAAAC" ,
"ABCDABC" };
int n = sizeof (txt) / sizeof (txt[0]);
for ( int i = 0; i < n; i++)
isRepeat(txt[i]) ? cout << "True\n"
: cout << "False\n" ;
return 0;
}
|
C
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
void computeLPSArray( char str[], int M, int lps[])
{
int len = 0;
int i;
lps[0] = 0;
i = 1;
while (i < M) {
if (str[i] == str[len]) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1];
}
else
{
lps[i] = 0;
i++;
}
}
}
}
bool isRepeat( char str[])
{
int n = strlen (str);
int lps[n];
computeLPSArray(str, n, lps);
int len = lps[n - 1];
return (len > 0 && n % (n - len) == 0) ? true : false ;
}
int main()
{
char txt[][100]
= { "ABCABC" , "ABABAB" , "ABCDABCD" ,
"GEEKSFORGEEKS" , "GEEKGEEK" , "AAAACAAAAC" ,
"ABCDABC" };
int n = sizeof (txt) / sizeof (txt[0]);
for ( int i = 0; i < n; i++)
isRepeat(txt[i]) ? printf ( "True\n" )
: printf ( "False\n" );
return 0;
}
|
Java
import java.io.*;
class GFG {
static void computeLPSArray(String str, int M,
int lps[])
{
int len = 0 ;
int i;
lps[ 0 ] = 0 ;
i = 1 ;
while (i < M) {
if (str.charAt(i) == str.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0 ) {
len = lps[len - 1 ];
}
else
{
lps[i] = 0 ;
i++;
}
}
}
}
static boolean isRepeat(String str)
{
int n = str.length();
int lps[] = new int [n];
computeLPSArray(str, n, lps);
int len = lps[n - 1 ];
return (len > 0 && n % (n - len) == 0 ) ? true
: false ;
}
public static void main(String[] args)
{
String txt[]
= { "ABCABC" , "ABABAB" , "ABCDABCD" ,
"GEEKSFORGEEKS" , "GEEKGEEK" , "AAAACAAAAC" ,
"ABCDABC" };
int n = txt.length;
for ( int i = 0 ; i < n; i++) {
if (isRepeat(txt[i]) == true )
System.out.println( "True" );
else
System.out.println( "False" );
}
}
}
|
Python3
def computeLPSArray(string, M, lps):
length = 0
i = 1
lps[ 0 ] = 0
while i < M:
if string[i] = = string[length]:
length + = 1
lps[i] = length
i + = 1
else :
if length ! = 0 :
length = lps[length - 1 ]
else :
lps[i] = 0
i + = 1
def isRepeat(string):
n = len (string)
lps = [ 0 ] * n
computeLPSArray(string, n, lps)
length = lps[n - 1 ]
if length > 0 and n % (n - length) = = 0 :
return True
else :
False
txt = [ "ABCABC" , "ABABAB" , "ABCDABCD" , "GEEKSFORGEEKS" ,
"GEEKGEEK" , "AAAACAAAAC" , "ABCDABC" ]
n = len (txt)
for i in range (n):
if isRepeat(txt[i]):
print ( True )
else :
print ( False )
|
C#
using System;
class GFG {
static void computeLPSArray(String str, int M,
int []lps)
{
int len = 0;
int i;
lps[0] = 0;
i = 1;
while (i < M)
{
if (str[i] == str[len])
{
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0)
{
len = lps[len-1];
}
else
{
lps[i] = 0;
i++;
}
}
}
}
static bool isRepeat(String str)
{
int n = str.Length;
int [] lps = new int [n];
computeLPSArray(str, n, lps);
int len = lps[n-1];
return (len > 0 && n % (n - len) == 0)
? true : false ;
}
public static void Main()
{
String[] txt = { "ABCABC" , "ABABAB" ,
"ABCDABCD" , "GEEKSFORGEEKS" ,
"GEEKGEEK" , "AAAACAAAAC" ,
"ABCDABC" };
int n = txt.Length;
for ( int i = 0; i < n; i++)
{
if (isRepeat(txt[i]) == true )
Console.WriteLine( "True" );
else
Console.WriteLine( "False" );
}
}
}
|
Javascript
<script>
function computeLPSArray(str, M, lps)
{
let len = 0;
let i;
lps[0] = 0;
i = 1;
while (i < M)
{
if (str[i] == str[len])
{
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0)
{
len = lps[len-1];
}
else
{
lps[i] = 0;
i++;
}
}
}
}
function isRepeat(str)
{
let n = str.length;
let lps = new Array(n);
lps.fill(0);
computeLPSArray(str, n, lps);
let len = lps[n-1];
return (len > 0 && n % (n - len) == 0)
? true : false ;
}
let txt = [ "ABCABC" , "ABABAB" ,
"ABCDABCD" , "GEEKSFORGEEKS" ,
"GEEKGEEK" , "AAAACAAAAC" ,
"ABCDABC" ];
let n = txt.length;
for (let i = 0; i < n; i++)
{
if (isRepeat(txt[i]) == true )
document.write( "True" + "</br>" );
else
document.write( "False" + "</br>" );
}
</script>
|
Output
True
True
True
False
True
True
False
Time Complexity: Time complexity of the above solution is O(n) as it uses KMP preprocessing algorithm which is linear time algorithm.
Auxiliary Space: O(n) because it is using extra space for array “lps”
Another approach:
Above problem can be solved with out using KMP algorithm and extra space.
This approach uses two pointers to check the minimum period of a String as a first step. Period of a String is the length of prefix substring which can be repeated x(x=length/period) times to construct the given string.
for eg: Input string “abcabcabcabc” is having a period 3. which means we can construct the given string by repeating first 3 characters 4 (length/3=4) number of times.
Approach:
- Initially set first pointer – i at 0th index of given string and second pointer – j at 1st index.
- check the characters at both index. if both matches, take period as (j-i) and increment i and j.
- if doesn’t match, Once again check if current character matches with first character at 0th index. if matches, update period as j(j-0=j) and set i to next character.
- f both characters not matches, set i to 0 and update period to -1.
- At the end check if the calculated period exactly divides the length of the string. if not, update period to -1. This check eliminates the presence of strings ending with suffix less than the period. for e.g period for the string “GEEKSFORGEEKS” is calculated as 8 but the suffix string(GEEKS) is having 5 characters only and is incomplete.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
int findPeriod(string A)
{
int length = A.size();
int period = -1;
int i = 0;
for ( int j = 1; j < length; j++) {
int currChar = A[j];
int comparator = A[i];
if (currChar == comparator) {
period = (j - i);
i++;
}
else {
if (currChar == A[0]) {
i = 1;
period = j;
}
else {
i = 0;
period = -1;
}
}
}
period = (length % period != 0) ? -1 : period;
return period;
}
int main()
{
vector<string> testStrings
= { "ABCABC" , "ABABAB" , "ABCDABCD" ,
"GEEKSFORGEEKS" , "GEEKGEEK" , "AAAACAAAAC" ,
"ABCDABC" };
int n = testStrings.size();
for ( int i = 0; i < n; i++) {
if (findPeriod(testStrings[i]) == -1)
cout << "false\n" ;
else
cout << "True\n" ;
}
return 0;
}
|
Java
import java.io.*;
class GFG {
public static int findPeriod(String A)
{
int length = A.length();
int period = - 1 ;
int i = 0 ;
for ( int j = 1 ; j < length; j++) {
int currChar = A.charAt(j);
int comparator = A.charAt(i);
if (currChar == comparator) {
period = (j - i);
i++;
}
else {
if (currChar == A.charAt( 0 )) {
i = 1 ;
period = j;
}
else {
i = 0 ;
period = - 1 ;
}
}
}
period = (length % period != 0 ) ? - 1 : period;
return period;
}
public static void main(String[] args)
{
String[] testStrings
= { "ABCABC" , "ABABAB" , "ABCDABCD" ,
"GEEKSFORGEEKS" , "GEEKGEEK" , "AAAACAAAAC" ,
"ABCDABC" };
int n = testStrings.length;
for ( int i = 0 ; i < n; i++) {
if (findPeriod(testStrings[i]) == - 1 )
System.out.println( "false" );
else
System.out.println( "True" );
}
}
}
|
Python3
def findPeriod(A):
length = len (A)
period = - 1
i = 0
for j in range ( 1 ,length):
currChar = A[j]
comparator = A[i]
if (currChar = = comparator):
period = (j - i)
i + = 1
else :
if (currChar = = A[ 0 ]):
i = 1
period = j
else :
i = 0
period = - 1
period = - 1 if (length % period ! = 0 ) else period
return period
testStrings = [ "ABCABC" , "ABABAB" , "ABCDABCD" , "GEEKSFORGEEKS" , "GEEKGEEK" , "AAAACAAAAC" , "ABCDABC" ]
n = len (testStrings)
for i in range (n):
if (findPeriod(testStrings[i]) = = - 1 ):
print ( "false" )
else :
print ( "True" )
|
C#
using System;
public class GFG{
public static int findPeriod(String A)
{
int length = A.Length;
int period = -1;
int i = 0;
for ( int j = 1; j < length; j++) {
int currChar = A[j];
int comparator = A[i];
if (currChar == comparator) {
period = (j - i);
i++;
}
else {
if (currChar == A[0]) {
i = 1;
period = j;
}
else {
i = 0;
period = -1;
}
}
}
period = (length % period != 0) ? -1 : period;
return period;
}
static public void Main (){
String[] txt = { "ABCABC" , "ABABAB" ,
"ABCDABCD" , "GEEKSFORGEEKS" ,
"GEEKGEEK" , "AAAACAAAAC" ,
"ABCDABC" };
int n = txt.Length;
for ( int i = 0; i < n; i++)
{
if (findPeriod(txt[i]) == -1)
Console.WriteLine( "False" );
else
Console.WriteLine( "True" );
}
}
}
|
Javascript
<script>
function findPeriod(A)
{
let length = A.length;
let period = -1;
let i = 0;
for (let j = 1; j < length; j++) {
let currChar = A[j];
let comparator = A[i];
if (currChar == comparator) {
period = (j - i);
i++;
}
else {
if (currChar == A[0]) {
i = 1;
period = j;
}
else {
i = 0;
period = -1;
}
}
}
period = (length % period != 0) ? -1 : period;
return period;
}
let testStrings = [ "ABCABC" , "ABABAB" , "ABCDABCD" , "GEEKSFORGEEKS" , "GEEKGEEK" , "AAAACAAAAC" , "ABCDABC" ];
let n = testStrings.length;
for (let i = 0; i < n; i++) {
if (findPeriod(testStrings[i]) == -1)
document.write( "false" , "</br>" );
else
document.write( "True" , "</br>" );
}
</script>
|
Output
True
True
True
false
True
True
false
Time Complexity : O(n)
Auxiliary Space : O(1)
Last Updated :
06 Feb, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...