Сравнение элементов массива, индекс выходит за пределы

avatar
just_curious
1 июля 2021 в 21:32
87
5
0

У меня есть фрагмент кода, и я немного не понимаю, как решить мою проблему, поэтому ознакомьтесь с приведенным ниже методом. Я пытался найти решение, но, к сожалению, ни одно из них не соответствовало моим потребностям, поэтому я ищу здесь совета. Метод берет строку и удаляет повторяющиеся символы, например - ввод: ABBCDEF должен возвращать ABCDEF, но при вводе i+1 на последней итерации я получил исключение IndexOutOfBound Exception, поэтому я могу выполнять итерацию до string.length-1, но затем я теряю последний элемент, какое на ваш взгляд САМОЕ УМНОЕ решение, спасибо.

public String removeDuplicates(String source){
        if(source.length() < 2){
            return source;
        }

        StringBuilder noDuplicates = new StringBuilder();
        char[] string = source.toCharArray();

        for(int i = 0; i < string.length-1; i++){
            if(string[i] != string[i+1]){
                noDuplicates.append(string[i]);
            }
        }
        return noDuplicates.toString();
    }
Источник
Andy Turner
1 июля 2021 в 21:38
2

Наиболее кратким решением, вероятно, будет return source.replaceAll("(.)\\1+", "$1");.

Ответы (5)

avatar
Andy Turner
1 июля 2021 в 21:41
0

Вы можете сделать это следующим образом: добавить первый символ в source, а затем добавить последующие символы, только если они не равны ранее добавленному символу.

if (source.isEmpty()) {
  return source; // Or "", it doesn't really matter.
}
StringBuilder sb = new StringBuilder();
sb.append(source.charAt(0));
for (int i = 1; i < source.length(); ++i) {
  char c = source.charAt(i);
  if (c != sb.charAt(sb.length() - 1)) {
    sb.append(c);
  }
}
return sb.toString();

Но если вы хотите сделать это более кратко, вы можете сделать это с помощью регулярного выражения:

return source.replaceAll("(.)\\1+", "$1");
Tim Hunter
2 июля 2021 в 14:07
0

Привет помошник. Я пытаюсь убедиться, что понимаю, как работает решение регулярного выражения... (.) выбирает любой символ в группу, \\1+ захватывает один или несколько символов в этой группе (которые непосредственно примыкают друг к другу, это не будет улавливать повторяющиеся символы не рядом друг с другом), а затем $1 находит конец строки, которую он настраивает, и добавляет символ, помещенный в группу (не уверен в этой интерпретации того, что он заменяет)?

Andy Turner
2 июля 2021 в 16:55
1

«и затем $1 находит конец строки» нет, это просто ссылка на группу захвата, то есть первый символ представляет собой последовательность повторяющихся символов.

avatar
jeff_hinton
1 июля 2021 в 22:32
0

Это как раз то, для чего был создан LinkedHashSet! Под капотом это HashSet с итератором для отслеживания порядка вставки, поэтому вы можете удалить дубликаты, добавив в набор, а затем восстановить строку с гарантированным порядком.

public static String removeDuplicates(String source) {
    Set<String> dupeSet = new LinkedHashSet<>();

    for (Character v : source.toCharArray()) {
        dupeSet.add(v.toString());
    }

    return String.join("", dupeSet);
}
avatar
Tim Hunter
1 июля 2021 в 22:08
0

Если вы хотите удалить все повторяющиеся символы независимо от их положения в заданном String, вы можете рассмотреть возможность использования метода chars(), который предоставляет IntStream символов и имеет метод distinct() для отфильтровать повторяющиеся значения. Затем вы можете собрать их вместе с помощью StringBuilder вот так:

public class RemoveDuplicatesTest {
  public static void main(String[] args) {
    String value = "ABBCDEFE";
    System.out.println("No Duplicates: " + removeDuplicates(value));
  }
  
  public static String removeDuplicates(String value) {
    StringBuilder result = new StringBuilder();
    value.chars().distinct().forEach(c -> result.append((char) c));
    return result.toString();
  }
}
avatar
firesnake
1 июля 2021 в 21:43
0

Простая логическая ошибка: Вы превращаете свою строку в массив символов. Это хорошо, но свойство длины любого массива покажет вам человеческий способ счета, если в нем что-то есть.

Если есть 1 элемент, длина будет 1
2 -> 2
3 -> 3
и т.д.
Вы поняли.

Поэтому, когда вы переходите к строке [i + 1], вы переходите на один символ дальше. Вы можете просто изменить условие прерывания на

i < = string.length - 2

Или вы можете написать итератор строки, чтобы получить доступ к следующему элементу, но это кажется излишним для этого примера

firesnake
1 июля 2021 в 22:15
0

Самым умным решением, вероятно, было бы использование выражения регулярного выражения, как написал @Andy Turner.

avatar
Henry Twist
1 июля 2021 в 21:36
0

Вы можете просто добавить последний символ после цикла:

public String removeDuplicates(String source){

    ...

    noDuplicates.append(string[string.length - 1]);
    return noDuplicates.toString();
}
just_curious
2 июля 2021 в 07:25
0

Да, но мне нужно другое условие if, чтобы проверить, не дублируются ли последние две буквы, потому что в предложенном вами решении мы это не проверяем. Поэтому я не могу просто добавить.

Henry Twist
2 июля 2021 в 09:53
0

Можете ли вы привести пример, когда это не сработает? Ваш цикл уже проверяет последние два, и если они дублируются, он никогда не добавляется.