ошибка: Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 7

При одних значениях s1 и s2 код работает, а при других нет.

import java.util.Arrays;

public class LeetCode {
    // метод для удаления символа из строки
    static String remove(String str, int a){
        String s = "";
        for (int i = 0; i < str.length(); i++){
            if (i != a){
                s = s + str.charAt(i);
            }
        }
        return s;
        
    }
    public static void main(String[] args) {
        String s1 = "aretheyhere";
        String s2 = "yestheyarehere";
        String s = s1 + s2;
        char[] chars = s.toCharArray();

        Arrays.sort(chars);
        String sorted = new String(chars);
        
        // удаление символа, если такой уже есть 
        for (int i = 0; i < sorted.length(); i++){
            for (int j = i + 1; j < sorted.length(); j++){
                while (sorted.charAt(i) == sorted.charAt(j)){
                    sorted = remove(sorted, j);
                }
            }
            
        }
        
        System.out.println(sorted);
    }
}

Ответы (1 шт):

Автор решения: Nowhere Man

Данное исключение указывает на выход за пределы строки при вызове метода String::charAt, который происходит при проверке условия в цикле while, так как внутри этого цикла строка "уменьшается" из-за вызова метода remove, а индексы i, j не меняются.

То есть, в случае продублированного символа в конце строки sorted код попытается найти символ за пределами этой строки.

Для исправления конкретно данной ошибки достаточно добавить проверку j < sorted.length():

while (j < sorted.length() && sorted.charAt(i) == sorted.charAt(j)) {
    sorted = remove(sorted, j);
}

Но в целом данное решение для задачи удаления дублированных символов из строки при помощи вспомогательного метода remove (с конкатенацией в цикле), который ещё и вызывается во вложенном цикле for, слишком медленное, так как имеет кубическую сложность O(N3), нивелируя быструю сортировку Arrays.sort.

Можно просто пропускать символы-дубликаты в массиве chars, и использовать StringBuilder для более эффективного получения строки-результата, содержащей только уникальные символы, отсортированные по алфавиту.

// ...
char[] chars = s.toCharArray();
Arrays.sort(chars);
        
StringBuilder sb = new StringBuilder();
        
for (int i = 0; i < chars.length; i++) {
    sb.append(chars[i]);
    while (i < chars.length - 1 && chars[i] == chars[i + 1]) {
        i++;
    }
}
        
String sorted = sb.toString();

Ещё более краткое решение с использованием Stream API может выглядеть так:

String streamlined = s.chars() // IntStream кодовых точек
    .sorted()    // сортируем символы (кодовые точки) из исходной строки
    .distinct()  // фильтруем: убираем дубликаты
     // создаём экземпляр StringBuilder и добавляем отфильтрованные уникальные символы
    .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) 
    .toString(); // конвертируем `StringBuilder` в строку `String`

System.out.println(streamlined);
→ Ссылка