«1. Введение

В этом руководстве мы покажем, как мы можем проверить в Java, является ли строка последовательностью повторяющихся подстрок.

2. Проблема

Прежде чем мы продолжим реализацию, давайте установим некоторые условия. Во-первых, предположим, что наша строка имеет как минимум два символа.

Во-вторых, есть хотя бы одно повторение подстроки.

Лучше всего это проиллюстрировать несколькими примерами, проверив несколько повторяющихся подстрок:

"aa"
"ababab"
"barrybarrybarry"

И несколько неповторяющихся:

"aba"
"cbacbac"
"carlosxcarlosy"

Сейчас мы покажем несколько решений проблемы.

3. Наивное решение

Давайте реализуем первое решение.

Процесс довольно прост: мы проверим длину строки и исключим односимвольные строки в самом начале.

Затем, поскольку длина подстроки не может быть больше половины длины строки, мы будем перебирать половину строки и создавать подстроку на каждой итерации, добавляя следующий символ к предыдущей подстроке. .

Затем мы удалим эти подстроки из исходной строки и проверим, равна ли длина \»разделенной\» подстроки нулю. Это будет означать, что он состоит только из своих подстрок:

public static boolean containsOnlySubstrings(String string) {

    if (string.length() < 2) {
        return false;
    }

    StringBuilder substr = new StringBuilder();
    for (int i = 0; i < string.length() / 2; i++) {
        substr.append(string.charAt(i));

        String clearedFromSubstrings 
          = string.replaceAll(substr.toString(), "");

        if (clearedFromSubstrings.length() == 0) {
            return true;
        }
    }

    return false;
}

Давайте создадим несколько строк для проверки нашего метода:

String validString = "aa";
String validStringTwo = "ababab";
String validStringThree = "baeldungbaeldung";

String invalidString = "aca";
String invalidStringTwo = "ababa";
String invalidStringThree = "baeldungnonrepeatedbaeldung";

И, наконец, мы можем легко проверить его правильность:

assertTrue(containsOnlySubstrings(validString));
assertTrue(containsOnlySubstrings(validStringTwo));
assertTrue(containsOnlySubstrings(validStringThree));

assertFalse(containsOnlySubstrings(invalidString));
assertFalse(containsOnlySubstrings(invalidStringTwo));
assertFalse(containsOnlySubstrings(invalidStringThree));

Хотя это решение работает, но оно не очень эффективно, так как мы перебираем половину строки и используем метод replaceAll() на каждой итерации.

Очевидно, это связано с затратами на производительность. Это будет работать за время O (n ^ 2).

4. Эффективное решение

Теперь мы проиллюстрируем другой подход.

А именно, мы должны использовать тот факт, что String состоит из повторяющихся подстрок тогда и только тогда, когда это нетривиальное вращение самой себя.

Ротация здесь означает, что мы удаляем некоторые символы из начала строки и помещаем их в конец. Например, «eldungba» — это вращение «baeldung». Если мы вращаем строку и получаем исходную, то мы можем применять это вращение снова и снова и получать строку, состоящую из повторяющихся подстрок.

Далее нам нужно проверить, так ли это в нашем примере. Для этого мы воспользуемся теоремой, которая гласит, что если строки A и строки B имеют одинаковую длину, то мы можем сказать, что A является вращением B тогда и только тогда, когда A является подстрокой BB. Если мы вернемся к примеру из предыдущего абзаца, мы сможем подтвердить эту теорему: baeldungbaeldung.

Поскольку мы знаем, что наша строка A всегда будет подстрокой AA, нам нужно только проверить, является ли строка A подстрокой AA, за исключением первого символа:

public static boolean containsOnlySubstringsEfficient(String string) {
    return ((string + string).indexOf(string, 1) != string.length());
}

Мы можем протестировать этот метод так же, как и предыдущий. На этот раз у нас O(n) временная сложность.

Мы можем найти несколько полезных теорем по этой теме в исследованиях по анализу строк.

5. Заключение

В этой статье мы проиллюстрировали два способа проверки того, состоит ли строка только из своих подстрок в Java.

Все примеры кода, использованные в статье, доступны на GitHub.