アナグラムアルゴリズムを作成したいのですが、このコードが機能しません。私のせいはどこですか?たとえば、desとsedはアナグラムですが、出力はアナグラムではありません。一方、文字列メソッドを使用する必要があります。配列ではありません。 :)
public static boolean isAnagram(String s1 , String s2)
{
String delStr="";
String newStr="";
for(int i=0;i<s1.length();i++)
{
for(int j=0 ; j < s2.length() ; j++)
{
if(s1.charAt(i)==s2.charAt(j))
{
delStr=s1.substring(i,i+1);
newStr=s2.replace(delStr,"");
}
}
}
if(newStr.equals(""))
return true;
else
return false;
}
より簡単な方法は、両方の文字列の文字を並べ替えて、それらが等しいかどうかを比較することです。
public static boolean isAnagram(String s1, String s2){
// Early termination check, if strings are of unequal lengths,
// then they cannot be anagrams
if ( s1.length() != s2.length() ) {
return false;
}
s1=s1.toLowerCase();
s2=s2.toLowerCase();
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
Arrays.sort(c1);
Arrays.sort(c2);
String sc1 = new String(c1);
String sc2 = new String(c2);
return sc1.equals(sc2);
}
個人的には、ネストされたforループ= pよりも読みやすいと思います
これにはO(n log n)実行時の複雑さがあります。ここで、n
は長い文字列の長さです。
編集:これは最適なソリューションではありません。最も効率的なアプローチ(つまり、面接で実際に何を言うべきか)については、@ aam1rの回答を参照してください。
これは定数空間を使用した線形時間で実行できます。始めるのに役立つ擬似コードは次のとおりです。
// Create new hashtable/hashmap to keep track of how many times each character
// is being used
character_map -> new hash map
// Initial check. If lengths are not the same, they can't be anagrams.
if s1.length != s2.length:
throw exception "Not anagrams"
// Add all characters from s1 to hashmap. Increment the value to keep track of
// number of occurences
foreach character c1 in s1:
character_map[c1]++
// Iterate through all character in s2 and decrement count of each character.
foreach character c2 in s2:
character_map[c2]--
// If they are anagrams, each character should be at "0" count at the point.
// If we come across a character that is not, it means that they are not anagrams
foreach key k, value v in character_map:
if v != 0:
throw exception "Not anagrams"
このコードはソートされないため、単純なループを使用して実行できます。全体の実行時間はO(n)で、全体のスペースはO(1)-したがって、最速のソリューションです。ハッシュマップは一定です(つまり、アルファベットセットにいくつのアイテムがあるかがわかります)。
if(s1.charAt(i)==s2.charAt(j))
delStr=s1.substring(i,i+1);
newStr=s2.replace(delStr,"");
このコードは、ステートメントが1つしかない場合でも、if
の周りに常にcurly braces
が必要な理由を示す優れたデモンストレーションです。 2番目の割り当ては実際にはif-condition
の外にあり、常に発生します。
2つの文字列がAnagram
であることを確認する最良の方法は、それらを文字配列(String#toCharArray)
に変換することです。次に、Arrays.sort
メソッドを使用してそれらを並べ替えます。そして、それらを比較します。
更新:-
String
メソッドを使用したいだけの場合は、実際にはネストされたループは必要ありません。あなたはたった1つでそれをすることができます。
これがあなたの修正されたコードです:-
public static boolean isAnagram(String s1 , String s2){
if (s1.length() != s2.length()) {
return false;
}
for(int i = 0; i < s2.length(); i++) {
if( !s1.contains("" + s2.charAt(i))) {
return false;
}
s1 = s1.replaceFirst("" + s2.charAt(i), "");
s2 = s2.replaceFirst("" + s2.charAt(i), "");
}
return true;
}
より効率的なのは、文字列をソートされた順序で比較することです。
public static boolean isAnagram(String s1 , String s2) {
return s1.length() == s2.length()
&& checkSum(s1) == checkSum(s2)
&& Arrays.equals(lettersSorted(s1), lettersSorted(s2));
}
static long checkSum(String s) {
long sqrSum = 0;
for(int i = 0; i < s.length(); s++) {
char ch = s.charAt(i);
sqrSum += ch + (1L << ch);
}
}
static char[] lettersSorted(String s) {
char[] chars = s.toCharArray();
Arrays.sort(chars);
return chars;
}
これはO(N ln N)アルゴリズムですが、文字列が通常アナグラムでない場合、平均してO(N)になります。
何をしようとしているのかわかりませんが、機能しないことは間違いありません(O(n^2)
で実行されます。これを試してください(O(n log n)
で実行されます)。 )代わりに:
public static boolean isAnagram(String s1, String s2){
if (s1.length() != s2.length()) return false;
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
Arrays.sort(c1);
Arrays.sort(c2);
for(int i = 0; i < c1.length; i++) {
if(c1[i] != c2[i]) return false;
}
return true;
}
文字列がアナグラムであるかどうかを判断するには、さまざまな解決策が考えられます。 1. Array.sort()
定義済みメソッドを使用する
_String string1 = "abc";
String string2 = "bca";
char[] chars = string1.toCharArray();
char[] chars2 = string2.toCharArray();
Arrays.sort(chars);
Arrays.sort(chars2);
string1 = new String(chars);
string2 = new String(chars2);
if (string1.equalsIgnoreCase(string2)) {
System.out.println("Anagram");
} else {
System.out.println("Not Anagram");
}
_
時間計算量:Ω(n log n)
2。反復法による
_char [] charArray = str.toCharArray();
if(str.length() == str1.length()){
for(char ch : charArray){
if(str1.indexOf(ch) == -1){
System.out.println("Not Anagram");
}
}
System.out.println("Anagram");
} else {
System.out.println("Not Anagram");
}
_
時間計算量:Ω(n)
ただし、最初のアルゴリズムはより読みやすく、2番目のアルゴリズムは実際に高速に実行されます。
それが機能しない理由:
例として「des」と「sed」を使用します。
一致する最後の反復で、以下を評価します。
if(s1.charAt(i)==s2.charAt(j))
{
delStr=s1.substring(i,i+1);
newStr=s2.replace(delStr,"");
}
これは次のようになります:if( "s" == "s")
次に、ifブロックに入り、評価します
newStr = "sed".replace("s","");
空の文字列の代わりに「ed」が表示されます。
物語の教訓は、あなたは常にs2から1文字を差し引いた文字を置き換えているということです。これは決して空になることはありません。
String.replace()を使用すると、デフォルトで文字のすべてのインスタンスが置き換えられるため、とにかく悪いです。 String.replace()を使用すると、「sed」は「seeeeeeed」のアナグラムと見なされます。 String.replaceFirst()を使用することをお勧めします。
いずれの場合も、開始点は次の変更を行うことです。
String newStr = s2;
...
// inside if block
newStr = newStr.replaceFirst( delStr, "" );
import Java.util.Scanner;
public class Anagrams {
static boolean isAnagram(String a, String b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a.length() != b.length()) {
return false;
}
char[] chars = a.toCharArray();
for (char c : chars) {
int index = b.indexOf(c);
if (index != -1) {
b = b.substring(0, index) + b.substring(index + 1, b.length());
} else {
return false;
}
}
return b.isEmpty();
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String a = scan.next();
String b = scan.next();
scan.close();
boolean ret = isAnagram(a, b);
System.out.println((ret) ? "Anagrams" : "Not Anagrams");
}
}
これは、int [256]を初期化せずに、英語のアルファベットのint [26]を初期化する別の提案です。
public static void main(String[] args) {
System.out.println(isAnagram("restful", "fluster"));
}
static boolean isAnagram(String s1, String s2) {
if (s1.length() != s2.length()) {
return false;
}
int[] countArray = new int[26];
for (int i = 0; i < s1.length(); i++) {
countArray[getIndex(i, s1)]++;
countArray[getIndex(i, s2)]--;
}
for (int i = 0; i < countArray.length; i++) {
if (countArray[i] != 0) {
return false;
}
}
return true;
}
public static int getIndex(int position, String value) {
return value.charAt(position) - 'a';
}
最高のジョージTsopouridis
以下は、2つの文字列が両方の文字列の1回の反復でアナグラムであるかどうか、および256要素配列の最後の反復であるかどうかを判断する簡潔なコードスニペットです。このアプローチでは、マッピング配列に文字数を記録することにより、文字列内の文字の並べ替えや、文字列/文字配列との間の変換を回避します。
static boolean isAnagram(String s1, String s2) {
if (s1.length() != s2.length()) return false;
int n = s1.length();
int[] charMap = new int[256];
for (int i = 0; i < n; i++) {
char c1 = s1.charAt(i);
charMap[c1]++;
char c2 = s2.charAt(i);
charMap[c2]--;
}
for (int i = 0; i < charMap.length; i++) {
if (charMap[i] != 0) return false;
}
return true;
}
このコードは基本的に、文字に対応する配列内のインデックス位置をインクリメントおよびデクリメントします。反復の終了時に配列要素のいずれかがゼロ以外の場合、インクリメントとデクリメントの量が等しくないため、文字列には異なる文字が含まれ、互いにアナグラムにすることはできません。
このアルゴリズムが2つの同じサイズの文字列を1回繰り返すとすると、実行時間はO(n)になります。 charMapは文字セットの要件に応じて常に一定であるため、スペースの複雑さはO(1)です。
public class SampleAnagram {
public static void main(String ...s) {
String s1 = "work";
String s2="kwro";
System.out.println(s1.charAt(0));
int s1L = s1.length();
int s2L = s2.length();
int totalCount = 0;
for(int i=0;i<s1L;i++) {
for(int j=0;j<s2L;j++) {
if(s1.charAt(i)==(s2.charAt(j))) {
totalCount = totalCount+1;
}
}
}
System.out.println(totalCount);
if(s1.length()==totalCount && s2.length()==totalCount) {
System.out.println("given the input as anagram");
}
}
}
public boolean checkAnagram(String s, String t) {
s = s.toLowerCase();
t = t.toLowerCase();
// We can ignore blanks
char[] Word1 = s.replaceAll("\\s","").toCharArray();
char[] Word2 = t.replaceAll("\\s","").toCharArray();
// Anagrams length should be the same
if (Word1.length != Word2.length) {
return false;
}
// Sorting arrays is pretty fast, it can be O(logn)
Arrays.sort(Word1);
Arrays.sort(Word2);
if (Arrays.equals(Word1, Word2)) {
return true;
}
return false;
}
Using HashMap
public boolean isAnagram(String Word, String anagram) {
if (Word.length() != anagram.length())
return false;
int count = 0;
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < Word.length(); i++) {
if (!map.containsKey(Word.charAt(i)))
map.put(Word.charAt(i), 1);
else
map.put(Word.charAt(i), map.get(Word.charAt(i)) + 1);
}
for (int i = 0; i < anagram.length(); i++) {
if (!map.containsKey(anagram.charAt(i)))
return false;
else if (map.get(anagram.charAt(i)) >= 1)
map.put(anagram.charAt(i), map.get(anagram.charAt(i)) - 1);
else
return false;
}
return true;
}
念のために言っておきますが、s1がs2のアナグラムであるかどうかを確認しようとしていますか?これは、s2がs1のアナグラムであることも意味します。したがって、s1とs2を並べ替えて、それらが等しいかどうかを確認します。
String string1 = "fdafdas";
String string2 = "fdwqkjl";
char[] chars = string1.toCharArray();
char[] chars2 = string2.toCharArray();
Arrays.sort(chars);
Arrays.sort(chars2);
string1 = new String(chars);
string2 = new String(chars2);
if (string1.equals(string2)) {
//They are an anagram
}
import Java.util.Scanner;
public class JavaProgram
{
public static void main(String[] input)
{
String str1, str2;
int len, len1, len2, i, j, found=0, not_found=0;
Scanner scan = new Scanner(System.in);
System.out.print("Enter First String : ");
str1 = scan.nextLine();
System.out.print("Enter Second String : ");
str2 = scan.nextLine();
len1 = str1.length();
len2 = str2.length();
if(len1 == len2)
{
len = len1;
for(i=0; i<len; i++)
{
found = 0;
for(j=0; j<len; j++)
{
if(str1.charAt(i) == str2.charAt(j))
{
found = 1;
break;
}
}
if(found == 0)
{
not_found = 1;
break;
}
}
if(not_found == 1)
{
System.out.print("Strings are not Anagram to Each Other..!!");
}
else
{
System.out.print("Strings are Anagram");
}
}
else
{
System.out.print("Both Strings Must have the same number of Character to be an Anagram");
}
}
}
これは複雑さO(2n)で機能すると思います
public static boolean isAnagram(String str1, String str2){
if(str1.length() != str2.length()){ return false;}
int[] buffer = new int[256];
for(char ch : str1.toCharArray()){
buffer[ch]++;
}
for(char ch : str2.toCharArray()){
if(buffer[ch]==0) return false;
buffer[ch] = (buffer[ch] > 0)?(buffer[ch] - 1 ): -1 ;
}
return true;
}
実際にロジックを書き留めて、アナグラムであるかどうかにかかわらず、2つの文字列をチェックするコードを書くために少し時間をかけました。もちろん、上記の答えの助けを借りて! XD
public static void main(String[] args) {
Map<Character, Integer> char_map = new HashMap<Character, Integer>();
Map<Character, Integer> empty_map = new HashMap<Character, Integer>();
String a = "HelloP";
String b = "HePlol";
if (a.length() != b.length()) {
System.out.println("false");
System.exit(0);
}
for (char c : a.toLowerCase().toCharArray()) {
empty_map.put(c, 0);
if (char_map.containsKey(c))
char_map.put(c, 1 + char_map.get(c));
else
char_map.put(c, 1);
}
for (char c : b.toLowerCase().toCharArray())
if (char_map.containsKey(c))
char_map.put(c, char_map.get(c) - 1);
System.out.println(char_map.equals(empty_map));
}
これは主にJava完全なコードはここにあります https://github.com/rdsr/algorithms/blob/master/src/jvm/misc/AnagramsList)に依存するより単純なアプローチです。 Java (これは関連する別の問題を解決することに注意してください)
class Anagram {
Map<Character, Integer> anagram;
Anagram(String s) {
anagram = new HashMap<Character, Integer>();
for (final Character c : s.toCharArray()) {
if (anagram.containsKey(c)) {
anagram.put(c, 1 + anagram.get(c));
} else {
anagram.put(c, 1);
}
}
}
@Override
public int hashCode() {
//.. elided
}
@Override
public boolean equals(Object obj) {
//.. elided
}
}
public class Anagrams {
public static void main(String[] args) {
System.out.println(new Anagram("abc").equals(new Anagram("bac")));
}
}
アナグラムについての就職の面接のテストをした後。 githubアカウントにアップロードしました。 Javaコードは、テキストファイル(複数行)がアナグラム詩またはアナグラムテキストであるかどうかをチェックします。
https://github.com/javocsoft/anagram_poem_checker
それが役に立てば幸い!
さようなら。
単純な理由は、replace関数が新しいString
オブジェクトを作成するためです。実際の文字列には何もしません(あなたの場合はs2
)、Javaでは、文字列は本質的に最終的なものであるためです。したがって、cmonkeyが指摘しているように、文字列s2から常に1文字を削除していますが、実際には、新しいString
オブジェクトが1文字少なく作成され、s2はそのままです。
あなたのケースでこれを機能させる簡単な方法は、新しい文字列オブジェクトを作成し、それを自分自身に割り当てることです。
{
s2=s2.replace(delString,"");
....
if(s2.empty()) return true;
return false;
}
次の解決策はO(n)
複雑だと思います。誰かが違う場合は、私に知らせてください。
import Java.util.HashMap;
import Java.util.Scanner;
public class Anagrams {
static boolean isAnagram(String Word1, String Word2)
{
if(Word1.length() != Word2.length()) {
return false;
}
int flag=0;
HashMap<Character,Integer> table = new HashMap<Character,Integer>();
for(int i=0; i< Word1.length();i++) {
table.put(Word1.charAt(i),1);
}
for(int i=0; i< Word2.length();i++) {
if(table.containsKey(Word2.charAt(i))) {
continue;
} else {
flag=1;
break;
}
}
return flag == 0;
}
public static void main(String[] args) {
System.out.println("Enter your string");
Scanner sc= new Scanner(System.in);
String Word1= sc.nextLine();
String Word2=sc.nextLine();
boolean result = isAnagram(Word1,Word2);
if(result) {
System.out.println("The words are Anagrams");
} else{
System.out.println("The words are not Anagrams");
}
}
}
public static boolean isAnagram(String s1, String s2) {
boolean aux = true;
if (s1.length() != s2.length()){
aux = false;
}else{
for (int i = 0; i < s1.length(); i++)
if(s2.toUpperCase().indexOf(s1.toUpperCase().substring(i, i+1)) == -1) aux = false;
}
return aux;
}
これがあなたの視点からの私の解決策です
private static boolean isAnagram(String s1, String s2){
int count = 0;
boolean flag = false;
if(s1.length() != s2.length()){
return false;
}
//checks whether both Word's letters are the same
for (int i = 0; i < s1.length(); i++){
for (int j = 0; j < s2.length(); j++){
if(s1.charAt(i) == s2.charAt(j)){
count++;
break;
}
}
}
//if count equals to one of the Strings length then it is an anagram
if(count == s2.length() ){
flag = true;
}
return flag;
}
public static boolean isAnagram(String s1, String s2) {
if (s1.length() != s2.length()) {
return false;
}
Map<Character, Integer> frequencies = new HashMap<>();
for (int i = 0; i < s1.length(); i++) {
if (frequencies.containsKey(s1.charAt(i))) {
frequencies.put(s1.charAt(i), frequencies.get(s1.charAt(i)) + 1);
} else {
frequencies.put(s1.charAt(i), 1);
}
}
for (int i = 0; i < s2.length(); i++) {
if (frequencies.containsKey(s2.charAt(i))) {
int frequency = frequencies.get(s2.charAt(i));
if (--frequency == 0) {
frequencies.remove(s2.charAt(i));
} else {
frequencies.put(s2.charAt(i), frequencies.get(s2.charAt(i)) - 1);
}
}
}
return frequencies.isEmpty();
}
アナグラム部分文字列にビットベクトルアプローチを使用するより高速なバージョン
public boolean isAnagram(String _source1, String _source2)
{
int flag = 0, char_index = 0, counter = 0;
if(_source2.length() < _source1.length()){
return false;
}
char[] _stringchar = _source1.toCharArray();
char[] _tocheck = _source2.toCharArray();
for(char character : _stringchar)
{
char_index = character - 'a';
if((flag & (1 << char_index)) == 0)
flag |= (1 << char_index);
}
for(char toCheckcChar : _tocheck)
{
char_index = toCheckcChar - 'a';
if((flag & (1 << char_index)) > 0)
counter++;
else
counter = 0;
if(counter == _source1.length())
return true;
}
return false;
}
public boolean isAnagram(String a, String b) {
boolean result = false;
final String one = a.replaceAll("[\\s+\\W+]", "").toLowerCase();
final String two = b.replaceAll("[\\s+\\W+]", "").toLowerCase();
if (one.length() == two.length()) {
final char[] oneArray = one.toCharArray();
final char[] twoArray = two.toCharArray();
Arrays.sort(oneArray);
Arrays.sort(twoArray);
result = Arrays.equals(oneArray, twoArray);
}
return result;
}
String str1="Mother In Law";
String str2="Hitler Woman";
char[] anag1=str1.replaceAll("\\s", "").toLowerCase().toCharArray();
char[] anag2=str2.replaceAll("\\s", "").toLowerCase().toCharArray();
Arrays.sort(anag1);
Arrays.sort(anag2);
System.out.println(Arrays.equals(anag1, anag2)? "words are anagrams":"words are not anagrams");
public class Anagram {
public boolean isAnagram(
String left,
String right) {
if (left.length() == right.length()) {
Map<Character, Integer> map = new HashMap<>();
char[] a = left.toCharArray(), b = right.toCharArray();
for (int i = 0; i < a.length; i++) {
accumulate(map, a[i]);
accumulate(map, b[i]);
}
for (char c : map.keySet()) {
if (map.get(c) > 0) {
return false;
}
}
return true;
} else {
return false;
}
}
private void accumulate(
Map<Character, Integer> map,
char key) {
if (map.containsKey(key)) {
map.put(key, Math.abs(map.get(key) - 1));
} else {
map.put(key, 1);
}
}
}
これは、HashMapの代わりに配列を使用するために作成したJava実装です。これにより、スペースが節約され、配列は非常に高速です。
public static boolean anagram(String s, String t) {
if (s.length() != t.length()) return false;
int[] arr = new int[123];
for (char c : s.toCharArray())
arr[c]++;
for (char c : t.toCharArray())
arr[c]--;
for (int i : arr)
if (i != 0)
return false;
return true;
}
ソートを一切行わず、マップを1つだけ使用するO(n)ソリューション。また、他のソリューションにない適切なnullチェックを追加しました。
public boolean isAnagram(String leftString, String rightString) {
if (leftString == null || rightString == null) {
return false;
} else if (leftString.length() != rightString.length()) {
return false;
}
Map<Character, Integer> occurrencesMap = new HashMap<>();
for(int i = 0; i < leftString.length(); i++){
char charFromLeft = leftString.charAt(i);
int nrOfCharsInLeft = occurrencesMap.containsKey(charFromLeft) ? occurrencesMap.get(charFromLeft) : 0;
occurrencesMap.put(charFromLeft, ++nrOfCharsInLeft);
char charFromRight = rightString.charAt(i);
int nrOfCharsInRight = occurrencesMap.containsKey(charFromRight) ? occurrencesMap.get(charFromRight) : 0;
occurrencesMap.put(charFromRight, --nrOfCharsInRight);
}
for(int occurrencesNr : occurrencesMap.values()){
if(occurrencesNr != 0){
return false;
}
}
return true;
}
あまり一般的ではありませんが、少し速いソリューションです。
public boolean isAnagram(String leftString, String rightString) {
if (leftString == null || rightString == null) {
return false;
} else if (leftString.length() != rightString.length()) {
return false;
}
char letters[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
Map<Character, Integer> occurrencesMap = new HashMap<>();
for (char l : letters) {
occurrencesMap.put(l, 0);
}
for(int i = 0; i < leftString.length(); i++){
char charFromLeft = leftString.charAt(i);
Integer nrOfCharsInLeft = occurrencesMap.get(charFromLeft);
occurrencesMap.put(charFromLeft, ++nrOfCharsInLeft);
char charFromRight = rightString.charAt(i);
Integer nrOfCharsInRight = occurrencesMap.get(charFromRight);
occurrencesMap.put(charFromRight, --nrOfCharsInRight);
}
for(Integer occurrencesNr : occurrencesMap.values()){
if(occurrencesNr != 0){
return false;
}
}
return true;
}
newStr = s2.replace(delStr、 "");の行を参照してください。
ここで行っていることは、s2のcharを置き換えて、newStrに割り当て直すことです。つまり、s2では何も変更していません。このコードを以下のコードに置き換えるだけで問題なく動作します
newStr = newStr.replace(delStr、 "");