Distinct Echo Substrings

hard string rolling hash

Problem

Given a string text, return the number of distinct non-empty substrings that can be written in the form a + a, that is, some string a immediately concatenated with an exact copy of itself (an "echo"). Two echo substrings are the same only if they are equal as strings, no matter where they occur.

Inputtext = "abcabcabc"
Output3
The distinct echoes are "abcabc" (a = "abc"), "bcabca" (a = "bca") and "cabcab" (a = "cab").

def distinct_echo_substrings(text):
    n = len(text)
    seen = set()
    for half in range(1, n // 2 + 1):
        for i in range(0, n - 2 * half + 1):
            a = text[i:i + half]
            b = text[i + half:i + 2 * half]
            if a == b:
                seen.add(a)
    return len(seen)
function distinctEchoSubstrings(text) {
  const n = text.length;
  const seen = new Set();
  for (let half = 1; half <= n / 2; half++) {
    for (let i = 0; i + 2 * half <= n; i++) {
      const a = text.slice(i, i + half);
      const b = text.slice(i + half, i + 2 * half);
      if (a === b) seen.add(a);
    }
  }
  return seen.size;
}
class Solution {
    public int distinctEchoSubstrings(String text) {
        int n = text.length();
        Set<String> seen = new HashSet<>();
        for (int half = 1; half <= n / 2; half++) {
            for (int i = 0; i + 2 * half <= n; i++) {
                String a = text.substring(i, i + half);
                String b = text.substring(i + half, i + 2 * half);
                if (a.equals(b)) seen.add(a);
            }
        }
        return seen.size();
    }
}
int distinctEchoSubstrings(string text) {
    int n = text.size();
    unordered_set<string> seen;
    for (int half = 1; half <= n / 2; half++) {
        for (int i = 0; i + 2 * half <= n; i++) {
            string a = text.substr(i, half);
            string b = text.substr(i + half, half);
            if (a == b) seen.insert(a);
        }
    }
    return (int)seen.size();
}
Time: O(n³) Space: O(n²)