LeetCode #459 Easy

Repeated Substring Pattern

Repeated Substring Pattern: decide whether a string can be built by repeating some substring block two or more times.

Constraints
  • 1 <= s.length <= 10⁴
  • s consists of lowercase English letters.
stringstring-matching
Open on LeetCode ↗
02

Intuition

Repeated substring pattern asks whether a string can be built by repeating one of its substrings two or more times. A direct approach tries every candidate length. A valid pattern's length must divide the string's length evenly, so only divisors need testing — and only up to n/2, since the pattern must repeat at least twice. For each divisor, check whether repeating that prefix reproduces the string. That is O(n√n) at worst and perfectly acceptable. The elegant solution is a single line, and worth understanding rather than memorising: - Concatenate the string with itself, strip the first and last characters, and check whether the original still appears inside. The reasoning: if s is p repeated k times, then s + s is p repeated 2k times. Removing one character from each end destroys the two original copies but leaves p repeated enough times that s still occurs somewhere in the middle. If s has no repeating pattern, the only occurrences of s within s + s are the two original ones, and stripping the ends removes both. The stripping is essential. Without it, s always appears in s + s and every string returns true. The KMP approach uses the failure function: n − lps[n-1] gives the shortest candidate period, and the string is periodic when that value divides n evenly and is not n itself. This is O(n) and is what the problem is really pointing at. A single-character string returns false, since a pattern must repeat at least twice.

How to spot this pattern

A repeating block's length must divide the string's length evenly, so only divisors up to n/2 need testing. Checking block * (n // length) == s verifies the whole construction in one comparison.

03

Approach

Try it first

Before reading on: price up what the direct approach costs here, then ask what you are recomputing on every character that could be carried instead. Aim for O(n^2) worst case time and O(n) space.

1

Test only divisor lengths

A valid pattern's length must divide n evenly, and be at most n/2 since it repeats twice or more. Only those candidates need checking.

2

Know the concatenation trick

Check whether s appears in (s + s) with the first and last characters removed. One line, and it answers the question completely.

3

Understand why it works

If s is p repeated k times, s + s is p repeated 2k times — stripping the ends destroys the two original copies but leaves s visible in the middle.

4

Never skip the stripping

Without removing the end characters, s always appears in s + s and every input returns true. The strip is what makes the test meaningful.

5

Or use the KMP failure function

n - lps[n-1] is the shortest candidate period. The string is periodic when that value divides n and is not n itself — O(n) and the intended solution.

6

Reject single characters

A one-character string cannot repeat twice, so the answer is false. The divisor loop handles this by never running.

7

Cost of the approaches

The divisor scan is O(n√n), the concatenation check O(n) with O(n) space, and KMP O(n) time and space.

04

Solution & live demo

▶1class Solution:
▶2 def repeatedSubstringPattern(self, s:
▶3 str) -> bool:
▶4 n = len(s)
▶5 for length in range(1, n // 2 + 1):
▶6 if n % length != 0:
▶7 continue
▶8 block = s[:length]
▶9 if block * (n // length) == s:
▶10 return True
▶11 return False
05

Common pitfalls

Testing lengths that don't divide n

✗ Wrong
for length in range(1, n // 2 + 1):
    block = s[:length]
    ...
✓ Right
if n % length != 0:
    continue

A block that doesn't tile the string exactly can never reconstruct it, so the work is wasted — and a naive comparison against a truncated repetition can produce a false positive on a partial final block.

Looping past n // 2

✗ Wrong
for length in range(1, n + 1):
✓ Right
for length in range(1, n // 2 + 1):

The pattern must repeat at least twice, so its length is at most half the string. Including n itself makes every string trivially match itself once and returns true for all input.

Comparing only the first two blocks

✗ Wrong
if s[:length] == s[length:2*length]: return True
✓ Right
if block * (n // length) == s:

Two matching blocks say nothing about the rest — "ababcd" passes that test and fails the real one. The full reconstruction has to be compared against the entire string.

06

Edge cases

string of length 1

no candidate length <= len(s)//2 exists, loop doesn't run, returns False

length is prime

only L=1 could divide it before len(s)//2, but a single repeated character rarely matches unless all chars are equal

whole string is one repeated character

L=1 divides and rebuilding matches immediately

length divides by multiple factors

smallest matching L is found first since the loop goes in increasing order

07

Complexity

Time
O(n^2) worst case
Space
O(n)
each candidate rebuild-and-compare is O(n); only divisors of n are tried