web-dev-qa-db-fra.com

Vérifier si deux chaînes sont des anagrammes l'une de l'autre en utilisant Java Java

J'écris le code suivant en Java Netbeans qui fonctionne assez bien pour les anagrammes normales. Mais si les deux champs de texte contiennent des mots qui contiennent des lettres répétitives, alors le code ne fonctionne pas. Quel peut être le problème et comment puis-je le résoudre? Je suis assez basique pour Java et je ne comprends pas encore les tableaux.

String s1= t1.getText(); 
String s2= t2.getText();  
int b=0,c=0;
if(s1.length()!=s2.length())
   System.out.print("No");
else {
   for(int i=0;i<s1.length();i++) {
      char s = s1.charAt(i);
      for(int j=0;j<s2.length();j++) {
         if(s==s2.charAt(j)){
            b++;
         } 
      }
      if(b==0)
         break;
   }
   if(b==0)
      System.out.print("No");
   else 
      System.out.print("YES");
} 
System.out.print(b);
7
Prakhar Londhe

J'irais pour quelque chose de plus simple à raisonner: deux chaînes sont des anagrammes si, une fois triées, elles correspondent exactement. Donc en Java ce serait quelque chose comme:

    String s1 = "cat";
    String s2 = "tac";
    boolean isAnagram = false;
    if (s1.length() == s2.length()) {
        char[] s1AsChar = s1.toCharArray();
        char[] s2AsChar = s2.toCharArray();
        Arrays.sort(s1AsChar);
        Arrays.sort(s2AsChar);
        isAnagram = Arrays.equals(s1AsChar, s2AsChar);
    } 
28
Ivan Valeriani

Voici ma solution, on compte l'apparence de chaque caractère dans la première chaîne puis on le soustrait du nombre dans la deuxième chaîne. Enfin, vérifiez si le nombre de caractères n'est pas 0, alors les deux chaînes ne sont pas des anagrammes.

public static boolean isAnagram(String a, String b){
    //assume that we are using ASCII
    int[] charCnt = new int[256];
    for(int i = 0; i < a.length(); i++){
        charCnt[a.charAt(i)]++;
    }
    for(int i = 0; i< b.length(); i++){
        charCnt[b.charAt(i)]--;
    }
    for(int i = 0; i<charCnt.length; i++){
        if(charCnt[i] != 0) return false;
    }
    return true;
}
9
Long Vu

Vous souhaitez comparer les caractères triés. C'est une ligne:

return Arrays.equals(s1.chars().sorted().toArray(),
    s2.chars().sorted().toArray());

Arrays.equals() compare les longueurs et tous les éléments pour vous.

9
Bohemian

Puisque vous semblez être un débutant, voici une solution qui n'implique pas de fonctions d'autres classes ou flux. Elle n'implique que l'utilisation de tableaux et le fait qu'un char peut également représenter un int.

public static void main(String[] args) throws ParseException {
    String s1= "anagram"; 
    String s2= "margana";  
    // We make use of the fact that a char does also represent an int.
    int lettersS1[] = new int[Character.MAX_VALUE];
    int lettersS2[] = new int[Character.MAX_VALUE];
    if(s1.length()!=s2.length())
       System.out.print("No");
    else {
       // Loop through the String once
       for(int i = 0; i<s1.length() ;++i) {
           // we can just use the char value as an index
           // and increase the value of it. This is our identifier how often 
           // each letter was aviable in the String. Alse case insensitive right now
           lettersS1[s1.toLowerCase().charAt(i)]++;
           lettersS2[s2.toLowerCase().charAt(i)]++;
       }
       // set a flag if the Strings were anagrams
       boolean anag = true;
       // We stop the loop as soon as we noticed they are not anagrams
       for(int i = 0;i<lettersS1.length&&anag;++i) {
           if(lettersS1[i] != lettersS2[i]) {
               // If the values differ they are not anagrams.
               anag = false;
           }
       }
       // Depending on the former loop we know if these two strings are anagrams
       if(anag) {
           System.out.print("Anagram");
       } else {
           System.out.print("No anagram");
       }
    } 
}
5
SomeJavaGuy

Une autre solution, basée sur le compteur d'occurrences:

static boolean areAnagrams(CharSequence a, CharSequence b) {
    int len = a.length();
    if (len != b.length())
        return false;

    // collect char occurrences in "a"
    Map<Character, Integer> occurrences = new HashMap<>(64);
    for (int i = 0; i < len; i++)
        occurrences.merge(a.charAt(i), 1, Integer::sum);

    // for each char in "b", look for matching occurrence
    for (int i = 0; i < len; i++) {
        char c = b.charAt(i);
        int cc = occurrences.getOrDefault(c, 0);
        if (cc == 0)                        
            return false;            
        occurrences.put(c, cc - 1);
    }
    return true;
}

Bien que cette solution soit moins élégante que "trier et comparer", elle pourrait être plus efficace pour les chaînes longues avec de petites chances d'être des anagrammes car elle fonctionne en O (n) au lieu de O (n logn) et retourne dès que l'occurrence correspondante n'est pas trouvée à une certaine position dans une deuxième chaîne.


Sortant du territoire "Java de base", j'ai modifié l'algorithme pour gérer également paires de substitution . Ici, les éléments collectés et mis en correspondance ne sont pas chars, mais int points de code:

static boolean areAnagrams(CharSequence a, CharSequence b) {
    int len = a.length();
    if (len != b.length())
        return false;

    // collect codepoint occurrences in "a"
    Map<Integer, Integer> ocr = new HashMap<>(64);
    a.codePoints().forEach(c -> ocr.merge(c, 1, Integer::sum));

    // for each codepoint in "b", look for matching occurrence
    for (int i = 0, c = 0; i < len; i += Character.charCount(c)) {
        int cc = ocr.getOrDefault((c = Character.codePointAt(b, i)), 0);
        if (cc == 0)                        
            return false;            
        ocr.put(c, cc - 1);
    }
    return true;
}
3
Alex Salauyou