文字列にアルファベットのすべての文字が含まれているかどうかを確認しようとしています。アルファベット全体を含むArrayList
を作成しました。文字列をchar配列に変換し、文字配列を反復処理し、ArrayList
に存在するすべての文字に対して要素を削除しています。最後に、Arraylist
が空かどうかを確認して、すべての要素が削除されたかどうかを確認しようとしています。これは、文字列にアルファベットのすべての文字が含まれていることを示します。
残念ながら、コードはarraylistから要素を削除するif条件内でIndexOutOfBoundsException
エラーをスローしています
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");
これらのソリューションはすべて、特にJava 8のストリームAPI:
/* Your lowercase string */.chars()
.filter(i -> i >= 'a' && i <= 'z')
.distinct().count() == 26;
編集:速度のため
ストリームの使用中にアルファベット全体が見つかったらすぐに文字列の反復を終了する場合は、内部で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
}
O(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の回答に追加して、List
を作成し、そこから削除することはまったく不要なようです。単に'a' - 'z'
をループし、各char
でチェックを行うことができます。さらに、各文字が存在するかどうかを確認するためにString
全体をループしています。しかし、より良いバージョンは、各文字自体をループすることです。これにより、数回の反復を強力に安全にすることができます。
最後に、簡単な例は次のようになります。
// 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
からint
に変換するため、List.remove(int)
を誤って使用しました。
実際に解決する方法は簡単です。 List.remove(Object)
を呼び出すようにするには
alphabets.remove((Character) inp);
その他の改善点:
Set
の代わりにList
を使用する必要があります。boolean[26]
を使用して、アルファベットが出現したかどうかを追跡することもできますstr.charAt(index)
を実行するだけで、特定の位置にキャラクターが表示されます。この情報を保存するには、1つの整数変数で十分です。このようにできます
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];
_
に
_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を取得する理由です。これは、97である 'a'のASCII
値をチェックしているためです。 'Characterに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
のすべてのメンバーをチェックします。並列ストリームを使用して文字列で。
Java 8の場合、次のように記述できます。
boolean check(final String input) {
final String lower = input.toLowerCase();
return IntStream.range('a', 'z'+1).allMatch(a -> lower.indexOf(a) >= 0);
}
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);
_
このアプローチは最速ではないかもしれませんが、コードはループやストリームなどを提案するソリューションよりも理解しやすいと思います。
次のようなことをしてください
sentence.split().uniq().sort() == range('a', 'z')
Character inp = strChar[i];
char
の代わりにこれを使用します。Listremoveメソッドには2つのオーバーロードメソッドがあり、1つはオブジェクト、もう1つはintです。charを渡すと、intメソッドとして扱われます。
文字列を小文字または大文字に変換します。次に、A-Zまたはa-zの同等のASCII 10進数値をループし、文字配列で見つからない場合は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;
}