«1. Обзор
В этом руководстве мы обсудим несколько способов удаления повторяющихся символов из строки в Java.
Для каждой техники мы также кратко расскажем о ее временной и пространственной сложности.
2. Использование Different
Давайте начнем с удаления дубликатов из нашей строки с помощью метода Different, представленного в Java 8.
Ниже мы получаем экземпляр IntStream из заданного строкового объекта. Затем мы используем отдельный метод для удаления дубликатов. Наконец, мы вызываем метод forEach для перебора отдельных символов и добавления их в наш StringBuilder:
StringBuilder sb = new StringBuilder();
str.chars().distinct().forEach(c -> sb.append((char) c));
Временная сложность: O(n) — время выполнения цикла прямо пропорционально размеру входная строка
Вспомогательный пробел: O(n) — поскольку для внутреннего использования Different использует LinkedHashSet, и мы также сохраняем результирующую строку в объекте StringBuilder
Поддерживает порядок: Да — поскольку LinkedHashSet поддерживает порядок его элементов
И, хотя приятно, что Java 8 так хорошо справляется с этой задачей, давайте сравним это с усилиями по развертыванию нашего собственного.
3. Использование indexOf
Наивный подход к удалению дубликатов из строки просто включает цикл по входу и использование метода indexOf для проверки того, существует ли уже текущий символ в результирующей строке:
StringBuilder sb = new StringBuilder();
int idx;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
idx = str.indexOf(c, i + 1);
if (idx == -1) {
sb.append(c);
}
}
Время Сложность: O(n * n) — для каждого символа метод indexOf проходит через оставшуюся строку
Вспомогательный пробел: O(n) — требуется линейное пространство, так как мы используем StringBuilder для хранения результат
Поддерживает порядок: Да
Этот метод имеет ту же сложность пространства, что и первый подход, но работает намного медленнее.
4. Использование массива символов
Мы также можем удалить дубликаты из нашей строки, преобразовав ее в массив символов, а затем перебрав каждый символ и сравнив его со всеми последующими символами.
Как видно ниже, мы создаем два цикла for и проверяем, повторяется ли каждый элемент в строке. Если найден дубликат, мы не добавляем его в StringBuilder:
char[] chars = str.toCharArray();
StringBuilder sb = new StringBuilder();
boolean repeatedChar;
for (int i = 0; i < chars.length; i++) {
repeatedChar = false;
for (int j = i + 1; j < chars.length; j++) {
if (chars[i] == chars[j]) {
repeatedChar = true;
break;
}
}
if (!repeatedChar) {
sb.append(chars[i]);
}
}
Временная сложность: O(n * n) — у нас есть внутренний и внешний цикл, которые обходят входную строку
Вспомогательный пробел: O(n) — требуется линейный пробел, поскольку переменная chars хранит новую копию введенной строки, и мы также используем StringBuilder для сохранения результата
Поддерживает порядок: Да
Опять же, наша вторая попытка работает плохо по сравнению с предложением Core Java, но давайте посмотрим, к чему мы придем со следующей попыткой.
5. Использование сортировки
В качестве альтернативы повторяющиеся символы можно удалить, отсортировав входную строку, чтобы сгруппировать дубликаты. Для этого нам нужно преобразовать строку в массив символов и отсортировать ее с помощью метода Arrays.sort. Наконец, мы пройдемся по отсортированному массиву символов.
На каждой итерации мы будем сравнивать каждый элемент массива с предыдущим элементом. Если элементы различаются, мы добавим текущий символ в StringBuilder:
StringBuilder sb = new StringBuilder();
if(!str.isEmpty()) {
char[] chars = str.toCharArray();
Arrays.sort(chars);
sb.append(chars[0]);
for (int i = 1; i < chars.length; i++) {
if (chars[i] != chars[i - 1]) {
sb.append(chars[i]);
}
}
}
Временная сложность: O(n log n) — сортировка использует быструю сортировку с двумя опорными точками, которая предлагает O(n log n). ) производительность на многих наборах данных
Вспомогательное пространство: O(n) — так как метод toCharArray делает копию входной строки
Поддерживает порядок: Нет
Давайте попробуем еще раз с нашей последней попыткой.
6. Использование набора
Еще один способ удалить повторяющиеся символы из строки — использовать набор. Если нас не волнует порядок символов в нашей выходной строке, мы можем использовать HashSet. В противном случае мы можем использовать LinkedHashSet для поддержания порядка вставки.
В обоих случаях мы будем перебирать входную строку и добавлять каждый символ в набор. Как только символы будут вставлены в набор, мы пройдемся по ним, чтобы добавить их в StringBuilder и вернуть результирующую строку:
StringBuilder sb = new StringBuilder();
Set<Character> linkedHashSet = new LinkedHashSet<>();
for (int i = 0; i < str.length(); i++) {
linkedHashSet.add(str.charAt(i));
}
for (Character c : linkedHashSet) {
sb.append(c);
}
Временная сложность: O(n) — время выполнения цикла прямо пропорционально к размеру входной строки
Вспомогательный пробел: O(n) — место, необходимое для Set, зависит от размера входной строки; также мы используем StringBuilder для хранения результата
«Поддерживает порядок: LinkedHashSet — да, HashSet — нет
И вот мы подошли к подходу Core Java! Не слишком шокирует то, что это очень похоже на то, что уже делает Different.
7. Заключение
В этой статье мы рассмотрели несколько способов удаления повторяющихся символов из строки в Java. Мы также рассмотрели временную и пространственную сложность каждого из этих методов.
Как всегда, фрагменты кода можно найти на GitHub.