Как проверить, содержит ли строка все буквы алфавита? [дубликат]
этот вопрос уже есть ответ здесь:
Я пытаюсь проверить, если строка содержит все буквы алфавита. Я создал ArrayList
который содержит весь алфавит. Я преобразовал строку в массив char, и я повторяю массив символов и для каждого символа, присутствующего в ArrayList
Я удаляю из него элемент. И в конце концов, я пытаюсь проверить, если Arraylist
пуст, чтобы увидеть, были ли удалены все элементы. Это означает, что строка содержит все буквы алфавита.
к сожалению, код бросает IndexOutOfBoundsException
ошибка внутри условия if, где я удаляю элементы из arraylist
List<Character> alphabets = new ArrayList<Character>();
alphabets.add('a');
alphabets.add('b');
alphabets.add('c');
alphabets.add('d');
alphabets.add('e');
alphabets.add('f');
alphabets.add('g');
alphabets.add('h');
alphabets.add('i');
alphabets.add('j');
alphabets.add('k');
alphabets.add('l');
alphabets.add('m');
alphabets.add('n');
alphabets.add('o');
alphabets.add('p');
alphabets.add('q');
alphabets.add('r');
alphabets.add('s');
alphabets.add('t');
alphabets.add('u');
alphabets.add('v');
alphabets.add('w');
alphabets.add('x');
alphabets.add('y');
alphabets.add('z');
// This is the string- I've just put a random example
String str = "a dog is running crazily on the ground who doesn't care about the world";
//Remove all the spaces
str = str.replace(" ", "");
// Convert the string to character array
char[] strChar = str.toCharArray();
for (int i = 0; i < strChar.length; i++) {
char inp = strChar[i];
if (alphabets.contains(inp)) {
alphabets.remove(inp);
}
}
if (alphabets.isEmpty())
System.out.println("String contains all alphabets");
else
System.out.println("String DOESN'T contains all alphabets");
16 ответов
все эти решения, похоже, делают много работы для относительно простой проверки, особенно учитывая API потока Java 8:
/* Your lowercase string */.chars()
.filter(i -> i >= 'a' && i <= 'z').distinct().count() == 26;
Edit: для скорости
если вы хотите завершить итерацию строки, как только будет найден весь алфавит, вы можете отслеживать с помощью HashSet
внутри:
Set<Integer> chars = new HashSet<>();
String s = /* Your lowercase string */;
s.length > 25 && s.chars()
.filter(i -> i >= 'a' && i <= 'z') //only alphabet
.filter(chars::add) //add to our tracking set if we reach this point
.filter(i -> chars.size() == 26) //filter the 26th letter found
.findAny().isPresent(); //if the 26th is found, return
таким образом, поток прекратится, как только Set
заполняется 26 символы.
есть некоторые (даже еще) больше эффективные решения с точки зрения производительности ниже, но в качестве личного замечания я скажу, чтобы не болтаться в преждевременной оптимизации слишком много, где вы могли бы иметь читаемость и меньше усилий при написании фактического кода.
List.remove
удаляет по индексу. Сchar
можно привести к int вы эффективно удаляете значения Индекса, которые не существуют, т. е. char 'a' равен int 97. Как вы можете видеть, в вашем списке нет 97 записей.
можно сделать alphabet.remove(alphabets.indexOf(inp))
;
как указано @Scary Wombat(https://stackoverflow.com/a/39263836/1226744) и @Kevin Esche (https://stackoverflow.com/a/39263917/1226744), лучшая альтернатива к вашему алгоритм
выражение - твой друг. Нет необходимости использовать List
здесь.
public static void main(String[] args) {
String s = "a dog is running crazily on the ground who doesn't care about the world";
s = s.replaceAll("[^a-zA-Z]", ""); // replace everything that is not between A-Za-z
s = s.toLowerCase();
s = s.replaceAll("(.)(?=.*\1)", ""); // replace duplicate characters.
System.out.println(s);
System.out.println(s.length()); // 18 : So, Nope
s = "a dog is running crazily on the ground who doesn't care about the world qwertyuioplkjhgfdsazxcvbnm";
s = s.replaceAll("[^a-zA-Z]", "");
s = s.toLowerCase();
s = s.replaceAll("(.)(?=.*\1)", "");
System.out.println(s);
System.out.println(s.length()); //26 (check last part added to String) So, Yes
}
о(n)
static Set<Integer> alphabet = new HashSet<>(26);
public static void main(String[] args) {
int cnt = 0;
String str = "a dog is running crazily on the ground who doesn't care about the world";
for (char c : str.toCharArray()) {
int n = c - 'a';
if (n >= 0 && n < 26) {
if (alphabet.add(n)) {
cnt += 1;
if (cnt == 26) {
System.out.println("found all letters");
break;
}
}
}
}
}
добавление в @Leon answer, создание List
и вынимать из него, кажется совершенно ненужным. Вы можете просто зациклиться 'a' - 'z'
и сделайте проверку с каждым char
. Кроме того, вы зацикливаетесь на всем String
чтобы узнать, присутствует ли каждая буква. Но лучшим вариантом было бы зацикливаться на каждой букве. Это может potentionally безопасный вам несколько итераций.
в конце простой пример может выглядеть так:
// This is the string- I've just put a random example
String str = "a dog is running crazily on the ground who doesn't care about the world";
str = str.toLowerCase();
boolean success = true;
for(char c = 'a';c <= 'z'; ++c) {
if(!str.contains(String.valueOf(c))) {
success = false;
break;
}
}
if (success)
System.out.println("String contains all alphabets");
else
System.out.println("String DOESN'T contains all alphabets");
другой ответ уже указал на причину исключения. Вы используете List.remove()
, так как он неявно преобразовать char
to int
, который называется List.remove(int)
которые удалить по индексу.
путь к решению на самом деле прост. Вы можете заставить его вызвать List.remove(Object)
by
alphabets.remove((Character) inp);
некоторые другие улучшения:
- вы должны использовать
Set
вместоList
в этом случае. - вы даже можете использовать
boolean[26]
отслеживать появился ли алфавит - вам не нужно преобразовывать строку в массив символов. Просто сделайте
str.charAt(index)
даст вам характер в определенном положении.
для хранения этой информации достаточно одной целочисленной переменной. Вы можете сделать это
public static boolean check(String input) {
int result = 0;
input = input.toLowerCase();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c >= 'a' && c <= 'z') {
result |= 1 << (input.charAt(i) - 'a');
}
}
return result == 0x3ffffff;
}
каждый бит соответствует букве в английском алфавите. Поэтому, если ваша строка содержит все буквы, результат будет иметь форму 00000011111111111111111111111111
Как насчет создания
List<String> alphabets = new ArrayList <String> ();
и добавьте значения в виде строк
затем
for (String val : alphabets) { // if str is long this will be more effecient
if (str.contains (val) == false) {
System.out.println ("FAIL");
break;
}
}
вы можете избавиться от исключения, изменив эту строку в своем коде
char inp = strChar[i];
to
Character inp = strChar[i];
см.https://docs.oracle.com/javase/7/docs/api/java/util/List.html#remove(java.lang.Object)
List.remove('char')
трактуется как List.remove('int')
, поэтому вы получаете indexOutOfBoundsException, потому что он проверяет ASCII
значение 'a', которое составляет 97. Преобразование переменной " inp " в символ вызовет List.remove('Object')
API-интерфейс.
и если вам нравится Java 8 потоков, как я:
final List<String> alphabets = new ArrayList<>();
и после заполнения алфавитов с a-z:
final String str = "a dog is running crazily on the ground who doesn't care about the world";
final String strAsLowercaseAndWithoutOtherChars = str.toLowerCase()
.replaceAll("[^a-z]", "");
final boolean anyCharNotFound = alphabets.parallelStream()
.anyMatch(t -> !strAsLowercaseAndWithoutOtherChars.contains(t));
if (anyCharNotFound) {
System.out.println("String DOESN'T contains all alphabets");
} else {
System.out.println("String contains all alphabets");
}
это преобразует строку в нижний регистр (пропустите, если вы действительно ищете только маленькие буквы), удаляет все символы из строки, которые не являются маленькими буквами, а затем проверяет все члены вашего alphabets
если они содержатся в строку с помощью параллельного потока.
вот еще одно наивное решение, которое использует String.split("")
разбить каждый символ на String[]
массив, а затем Arrays.asList()
чтобы преобразовать это в List<String>
. Затем вы можете просто позвонить yourStringAsList.containsAll(alphabet)
чтобы определить, является ли String
содержит алфавит:
String yourString = "the quick brown fox jumps over the lazy dog";
List<String> alphabet = Arrays.asList("abcdefghijklmnopqrstuvwxyz".split(""));
List<String> yourStringAsList = Arrays.asList(yourString.split(""));
boolean containsAllLetters = yourStringAsList.containsAll(alphabet);
System.out.println(containsAllLetters);
этот подход может быть не самым быстрым, но я думаю, что код немного легче понять, чем решения, предлагающие циклы, потоки и тому подобное.
для Java 8, это может быть записано так:
boolean check(final String input) {
final String lower = input.toLowerCase();
return IntStream.range('a', 'z'+1).allMatch(a -> lower.indexOf(a) >= 0);
}
преобразуйте строку в нижний регистр или заглавные буквы. Затем цикл через эквивалентные десятичные значения ascii для A-Z или a-z и возвращает false, если не найден в массиве символов. Вам придется бросить int в char.
Я думал об игре с ASCII-коды символов.
String toCheck = yourString.toLowerCase();
int[] arr = new int[26];
for(int i = 0; i < toCheck.length(); i++) {
int c = ((int) toCheck.charAt(i)) - 97;
if(c >= 0 && c < 26)
arr[c] = arr[c] + 1;
}
после выполнения цикла вы в конечном итоге получите массив счетчиков, каждый из которых представляет букву алфавита (индекс) и это вхождение в строке.
boolean containsAlph = true;
for(int i = 0; i < 26; i++)
if(arr[i] == 0) {
containsAlph = false;
break;
}
Character inp = strChar[i];
используйте это вместо char
, метод удаления списка имеет 2 перегруженных метода, один с object и один с int .Если вы передадите char, его будут рассматривать как int one.