webentwicklung-frage-antwort-db.com.de

So prüfen Sie, ob zwei Wörter Anagramme sind

Ich habe ein Programm, das Ihnen zeigt, ob zwei Wörter Anagramme voneinander sind. Es gibt einige Beispiele, die nicht richtig funktionieren werden, und ich würde mich über jede Hilfe freuen, auch wenn sie nicht fortgeschritten wäre, wäre das toll, da ich ein Programmierer im ersten Jahr bin. "schoolmaster" und "theclassroom" sind Anagramme voneinander, aber wenn ich "theclassroom" in "theclafsroom" umstelle, werden immer noch Anagramme angezeigt. Was mache ich falsch?

import Java.util.ArrayList;
public class AnagramCheck
{
  public static void main(String args[])
  {
      String phrase1 = "tbeclassroom";
      phrase1 = (phrase1.toLowerCase()).trim();
      char[] phrase1Arr = phrase1.toCharArray();

      String phrase2 = "schoolmaster";
      phrase2 = (phrase2.toLowerCase()).trim();
      ArrayList<Character> phrase2ArrList = convertStringToArraylist(phrase2);

      if (phrase1.length() != phrase2.length()) 
      {
          System.out.print("There is no anagram present.");
      } 
      else 
      {
          boolean isFound = true;
          for (int i=0; i<phrase1Arr.length; i++)
          {  
              for(int j = 0; j < phrase2ArrList.size(); j++) 
              {
                  if(phrase1Arr[i] == phrase2ArrList.get(j))
                  {
                      System.out.print("There is a common element.\n");
                      isFound = ;
                      phrase2ArrList.remove(j);
                  }
              }
              if(isFound == false)
              {
                  System.out.print("There are no anagrams present.");
                  return;
              } 
          }
          System.out.printf("%s is an anagram of %s", phrase1, phrase2);
      }
  }

  public static ArrayList<Character> convertStringToArraylist(String str) {
      ArrayList<Character> charList = new ArrayList<Character>(); 
      for(int i = 0; i<str.length();i++){
          charList.add(str.charAt(i));
      }
      return charList;
  }
}
42
Chilli

Der schnellste Algorithmus wäre, jedes der 26 englischen Zeichen einer eindeutigen Primzahl zuzuordnen. Berechnen Sie dann das Produkt der Zeichenfolge. Nach dem Grundsatz der Arithmetik sind 2 Strings genau dann Anagramme, wenn ihre Produkte gleich sind.

90
SeriousBusiness

Zwei Wörter sind Diagramme voneinander, wenn sie dieselbe Anzahl von Zeichen und dieselben Zeichen enthalten. Sie müssen nur die Zeichen in lexikographischer Reihenfolge sortieren und bestimmen, ob alle Zeichen in einer Zeichenfolge und in derselben Reihenfolge wie alle Zeichen in der anderen Zeichenfolge sind.

Hier ist ein Codebeispiel. Sehen Sie sich die API unter Arrays an, um zu verstehen, was hier vor sich geht.

public boolean isAnagram(String firstWord, String secondWord) {
     char[] Word1 = firstWord.replaceAll("[\\s]", "").toCharArray();
     char[] Word2 = secondWord.replaceAll("[\\s]", "").toCharArray();
     Arrays.sort(Word1);
     Arrays.sort(Word2);
     return Arrays.equals(Word1, Word2);
}
100
Makoto

Wenn Sie eines der Arrays sortieren, wird die Lösung zu O (n log n). Wenn Sie jedoch eine Hashmap verwenden, ist dies O (n). getestet und funktioniert.

char[] Word1 = "test".toCharArray();
char[] Word2 = "tes".toCharArray();

Map<Character, Integer> lettersInWord1 = new HashMap<Character, Integer>();

for (char c : Word1) {
    int count = 1;
    if (lettersInWord1.containsKey(c)) {
        count = lettersInWord1.get(c) + 1;
    }
    lettersInWord1.put(c, count);
}

for (char c : Word2) {
    int count = -1;
    if (lettersInWord1.containsKey(c)) {
        count = lettersInWord1.get(c) - 1;
    }
    lettersInWord1.put(c, count);
}

for (char c : lettersInWord1.keySet()) {
    if (lettersInWord1.get(c) != 0) {
        return false;
    }
}

return true;
48
jb.

Hier ist eine einfache schnelle O(n) - Lösung, ohne Sortierungen oder mehrere Schleifen oder Hash-Maps zu verwenden. Wir erhöhen den Zählwert jedes Zeichens im ersten Array und dekrementieren den Zählwert jedes Zeichens im zweiten Array. Wenn das resultierende Anzahlenfeld voller Nullen ist, sind die Zeichenfolgen Anagramme. Kann erweitert werden, um andere Zeichen einzuschließen, indem das Zählungsfeld vergrößert wird.

class AnagramsFaster{

    private static boolean compare(String a, String b){
        char[] aArr = a.toLowerCase().toCharArray(), bArr = b.toLowerCase().toCharArray();
        if (aArr.length != bArr.length)
            return false;
        int[] counts = new int[26]; // An array to hold the number of occurrences of each character
        for (int i = 0; i < aArr.length; i++){
            counts[aArr[i]-97]++;  // Increment the count of the character at i
            counts[bArr[i]-97]--;  // Decrement the count of the character at i
        }
        // If the strings are anagrams, the counts array will be full of zeros
        for (int i = 0; i<26; i++)
            if (counts[i] != 0)
                return false;
        return true;
    }

    public static void main(String[] args){
        System.out.println(compare(args[0], args[1]));
    }
}
25
Aswin

Viele Leute haben Lösungen vorgestellt, aber ich möchte nur über die algorithmische Komplexität einiger der gängigen Ansätze sprechen:

  • Die einfache Methode zum Sortieren der Zeichen mit Arrays.sort() lautet O(N log N).

  • Wenn Sie die Radix-Sortierung verwenden, reduziert sich dies auf O(N) mit O(M) space, wobei M die Anzahl der verschiedenen Zeichen im Alphabet ist. (Das sind 26 auf Englisch ... aber theoretisch sollten wir mehrsprachige Anagramme berücksichtigen.)

  • Das "Zählen der Zeichen" mit einem Array von Zählungen ist ebenfalls O(N) ... und schneller als das Sortieren nach Radix, da der sortierte String nicht rekonstruiert werden muss. Die Speicherplatznutzung wird O(M) sein.

  • Ein "Zählen der Zeichen" unter Verwendung eines Wörterbuchs, einer Hashmap, einer Baumkarte oder eines entsprechenden Objekts ist langsamer als das Array, wenn das Alphabet nicht sehr groß ist.

  • Der elegante Ansatz des "Produkt der Primzahlen" ist im schlimmsten Fall leider O(N^2). Dies liegt daran, dass bei lang genug Wörtern oder Ausdrücken das Produkt der Primzahlen nicht in eine long passt. Das bedeutet, dass Sie BigInteger verwenden müssen, und N-mal eine BigInteger multipliziert mit einer kleinen Konstanten ist O(N^2)

    Für ein hypothetisches großes Alphabet wird der Skalierungsfaktor groß sein. Die Verwendung des Produkts der Primzahlen im schlimmsten Fall als BigInteger ist (denke ich) O(N*logM).

  • Ein auf hashcode basierender Ansatz ist normalerweise O(N), wenn die Wörter keine Anagramme sind. Wenn die Hashcodes gleich sind, müssen Sie dennoch einen ordnungsgemäßen Anagrammtest durchführen. Dies ist also keine vollständige Lösung.

22
Stephen C

O (n) -Lösung ohne Sortierung und Verwendung nur einer Karte. 

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;
}

und weniger generische Lösung, aber etwas schneller. Sie müssen Ihr Alphabet hier platzieren:

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;
}
6
goroncy

Wir laufen zwei gleich lange Saiten und verfolgen die Unterschiede zwischen ihnen. Uns ist es egal, was die Unterschiede sind, wir möchten nur wissen, ob sie die gleichen Charaktere haben oder nicht. Dies ist in O(n/2) ohne Nachbearbeitung (oder viele Primzahlen) möglich.

public class TestAnagram {
  public static boolean isAnagram(String first, String second) {
    String positive = first.toLowerCase();
    String negative = second.toLowerCase();

    if (positive.length() != negative.length()) {
      return false;
    }

    int[] counts = new int[26];

    int diff = 0;

    for (int i = 0; i < positive.length(); i++) {
      int pos = (int) positive.charAt(i) - 97; // convert the char into an array index
      if (counts[pos] >= 0) { // the other string doesn't have this
        diff++; // an increase in differences
      } else { // it does have it
        diff--; // a decrease in differences
      }
      counts[pos]++; // track it

      int neg = (int) negative.charAt(i) - 97;
      if (counts[neg] <= 0) { // the other string doesn't have this
        diff++; // an increase in differences
      } else { // it does have it
        diff--; // a decrease in differences
      }
      counts[neg]--; // track it
    }

    return diff == 0;
  }

  public static void main(String[] args) {
    System.out.println(isAnagram("zMarry", "zArmry")); // true
    System.out.println(isAnagram("basiparachromatin", "marsipobranchiata")); // true
    System.out.println(isAnagram("hydroxydeoxycorticosterones", "hydroxydesoxycorticosterone")); // true
    System.out.println(isAnagram("hydroxydeoxycorticosterones", "hydroxydesoxycorticosterons")); // false
    System.out.println(isAnagram("zArmcy", "zArmry")); // false
  }
}

Ja, dieser Code ist vom englischen Zeichensatz ASCII mit Kleinbuchstaben abhängig, es sollte jedoch nicht schwierig sein, ihn in andere Sprachen zu ändern. Sie können immer eine Karte [Character, Int] verwenden, um die gleichen Informationen zu verfolgen. Dies ist nur langsamer.

4
Jeff Thomas

Viele komplizierte Antworten hier. Basierend auf der akzeptierten Antwort und dem Kommentar , der die 'ac' - 'bb'-Ausgabe erwähnt, unter der Annahme, dass A = 1 B = 2 C = 3 ist, könnten wir einfach das Quadrat jeder Ganzzahl verwenden, die ein Zeichen darstellt und löse das Problem:

public boolean anagram(String s, String t) {
    if(s.length() != t.length())
        return false;

    int value = 0;
    for(int i = 0; i < s.length(); i++){
        value += ((int)s.charAt(i))^2;
        value -= ((int)t.charAt(i))^2;
    }
    return value == 0;
}
3
chakming
    /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Algorithms;

import Java.util.ArrayList;
import Java.util.Arrays;
import Java.util.HashMap;
import javax.swing.JOptionPane;

/**
 *
 * @author Mokhtar
 */
public class Anagrams {

    //Write aprogram to check if two words are anagrams
    public static void main(String[] args) {
        Anagrams an=new Anagrams();
        ArrayList<String> l=new ArrayList<String>();
        String result=JOptionPane.showInputDialog("How many words to test anagrams");
        if(Integer.parseInt(result) >1)
        {    
            for(int i=0;i<Integer.parseInt(result);i++)
            {

                String Word=JOptionPane.showInputDialog("Enter Word #"+i);
                l.add(Word);   
            }
            System.out.println(an.isanagrams(l));
        }
        else
        {
            JOptionPane.showMessageDialog(null, "Can not be tested, \nYou can test two words or more");
        }

    }

    private static String sortString( String w )
    {
        char[] ch = w.toCharArray();
        Arrays.sort(ch);
        return new String(ch);
    }

    public boolean isanagrams(ArrayList<String> l)
    {
        boolean isanagrams=true; 
        ArrayList<String> anagrams = null;
        HashMap<String, ArrayList<String>> map =  new HashMap<String, ArrayList<String>>();
        for(int i=0;i<l.size();i++)
            {
        String Word = l.get(i);
        String sortedWord = sortString(Word);
            anagrams = map.get( sortedWord );
        if( anagrams == null ) anagrams = new ArrayList<String>();
        anagrams.add(Word);
        map.put(sortedWord, anagrams);
            }

            for(int h=0;h<l.size();h++)
            {
                if(!anagrams.contains(l.get(h)))
                {
                    isanagrams=false;
                    break;
                }
            }

            return isanagrams;
        //}
        }

}
3

Durch die Verwendung von mehr Arbeitsspeicher (einer HashMap mit höchstens N/2 Elementen) müssen wir die Zeichenfolgen nicht sortieren.

public static boolean areAnagrams(String one, String two) {
    if (one.length() == two.length()) {
        String s0 = one.toLowerCase();
        String s1 = two.toLowerCase();
        HashMap<Character, Integer> chars = new HashMap<Character, Integer>(one.length());
        Integer count;
        for (char c : s0.toCharArray()) {
            count = chars.get(c);
            count = Integer.valueOf(count != null ? count + 1 : 1);
            chars.put(c, count);
        }
        for (char c : s1.toCharArray()) {
            count = chars.get(c);
            if (count == null) {
                return false;
            } else {
                count--;
                chars.put(c, count);
            }
        }
        for (Integer i : chars.values()) {
            if (i != 0) {
                return false;
            }
        }
        return true;
    } else {
        return false;
    }
}

Diese Funktion wird tatsächlich in O(N) ... anstelle von O(NlogN) für die Lösung ausgeführt, die die Zeichenfolgen sortiert. Wenn ich davon ausgehen würde, dass Sie nur alphabetische Zeichen verwenden, könnte ich anstelle der Hashmap nur ein Array von 26 Ints (von a bis z ohne Akzente oder Dekorationen) verwenden.

Wenn wir das definieren: N = | one | + | two | Wir führen eine Iteration über N durch (einmal über eins, um die Zähler zu erhöhen, und einmal, um sie um zwei zu erniedrigen).

Die anderen beschriebenen Algorithmen haben einen Vorteil: Sie verwenden keinen zusätzlichen Speicher, vorausgesetzt Arrays.sort verwendet Inplace-Versionen von QuickSort oder die Zusammenführungssortierung. Da wir jedoch über Anagramme sprechen, gehe ich davon aus, dass wir über menschliche Sprachen sprechen. Daher sollten Wörter nicht lang genug sein, um Gedächtnisprobleme zu erzeugen.

Ich bin ein C++ - Entwickler und der folgende Code ist in C++. Ich glaube, der schnellste und einfachste Weg, dies zu tun, wäre folgender:

Erstellen Sie einen Vektor aus Zentimetern der Größe 26, wobei alle Slots auf 0 initialisiert sind, und platzieren Sie jedes Zeichen der Zeichenfolge an der entsprechenden Stelle im Vektor. Denken Sie daran, dass der Vektor in alphabetischer Reihenfolge ist. Wenn also der erste Buchstabe in der Zeichenfolge z ist, würde er in myvector gehen [26]. Hinweis: Dies kann mit ASCII Zeichen erfolgen, so dass Ihr Code im Wesentlichen so aussieht:

string s = zadg;
for(int i =0; i < s.size(); ++i){
    myvector[s[i] - 'a'] = myvector['s[i] - 'a'] + 1;
} 

Das Einfügen aller Elemente würde O(n) Zeit in Anspruch nehmen, da Sie die Liste nur einmal durchlaufen würden. Sie können jetzt genau dasselbe für die zweite Saite tun, und dies würde O(n) Zeit in Anspruch nehmen. Sie können die beiden Vektoren dann vergleichen, indem Sie prüfen, ob die Zähler in jedem Slot gleich sind. Wenn dies der Fall ist, bedeutet dies, dass Sie in beiden Zeichenfolgen die gleiche Anzahl JEDER Zeichen und somit Anagramme hatten. Der Vergleich der beiden Vektoren sollte auch O(n) Zeit in Anspruch nehmen, da Sie sie nur einmal durchlaufen. 

Hinweis: Der Code funktioniert nur für ein einzelnes Word-Zeichen. Wenn Sie Leerzeichen sowie Zahlen und Symbole haben, können Sie einfach einen Vektor der Größe 96 (ASCII-Zeichen 32-127) erstellen ASCII Liste der Zeichen.

Ich hoffe das hilft. Wenn ich irgendwo einen Fehler gemacht habe, bitte einen Kommentar hinterlassen.

3
muneebahmad

Danke, dass Sie darauf hingewiesen haben, einen Kommentar abzugeben. Während ich den Kommentar machte, stellte ich fest, dass eine falsche Logik vorlag. Ich habe die Logik korrigiert und für jeden Code einen Kommentar hinzugefügt.

// Time complexity: O(N) where N is number of character in String
// Required space :constant space.
// will work for string that contains ASCII chars

private static boolean isAnagram(String s1, String s2) {

    // if length of both string's are not equal then they are not anagram of each other 
    if(s1.length() != s2.length())return false;

    // array to store the presence of a character with number of occurrences.   
    int []seen = new int[256];

    // initialize the array with zero. Do not need to initialize specifically  since by default element will initialized by 0.
    // Added this is just increase the readability of the code. 
    Arrays.fill(seen, 0);

    // convert each string to lower case if you want to make ABC and aBC as anagram, other wise no need to change the case.  
    s1 = s1.toLowerCase();
    s2 = s2.toLowerCase();

    //  iterate through the first string and count the occurrences of each character
    for(int i =0; i < s1.length(); i++){
        seen[s1.charAt(i)] = seen[s1.charAt(i)] +1;
    }

    // iterate through second string and if any char has 0 occurrence then return false, it mean some char in s2 is there that is not present in s1.
    // other wise reduce the occurrences by one every time .
    for(int i =0; i < s2.length(); i++){
        if(seen[s2.charAt(i)] ==0)return false;
        seen[s2.charAt(i)] = seen[s2.charAt(i)]-1;
    }

    // now if both string have same occurrence of each character then the seen array must contains all element as zero. if any one has non zero element return false mean there are 
    // some character that either does not appear in one of the string or/and mismatch in occurrences 
    for(int i = 0; i < 256; i++){
        if(seen[i] != 0)return false;
    }
    return true;
}
2
Kuldeep Singh

Bislang arbeiten alle vorgeschlagenen Lösungen mit separaten char-Elementen, nicht mit Code-Punkten. Ich möchte zwei Lösungen vorschlagen, um Surrogat-Paare richtig zu behandeln (dies sind Zeichen von U + 10000 bis U + 10FFFF , die aus zwei char-Elementen bestehen).

1) Einzeilige O (n logn) - Lösung, die Java 8 CharSequence.codePoints() stream verwendet:

static boolean areAnagrams(CharSequence a, CharSequence b) {
    return Arrays.equals(a.codePoints().sorted().toArray(),
                         b.codePoints().sorted().toArray());
}

2) Weniger elegant O(n) Lösung (Tatsächlich ist es nur für lange Strings mit geringen Chancen, Anagramme zu sein):

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;
}
1
Alex Salauyou
import Java.util.ArrayList;
import Java.util.List;
import Java.util.Map;
import Java.util.TreeMap;
/**
 * Check if Anagram by Prime Number Logic
 * @author Pallav
 *
 */
public class Anagram {
    public static void main(String args[]) {
        System.out.println(isAnagram(args[0].toUpperCase(),
                args[1].toUpperCase()));
    }
/**
 * 
 * @param Word : The String 1
 * @param anagram_Word : The String 2 with which Anagram to be verified
 * @return true or false based on Anagram
 */
    public static Boolean isAnagram(String Word, String anagram_Word) {
        //If length is different return false
        if (Word.length() != anagram_Word.length()) {
            return false;
        }
        char[] words_char = Word.toCharArray();//Get the Char Array of First String
        char[] anagram_Word_char = anagram_Word.toCharArray();//Get the Char Array of Second String
        int words_char_num = 1;//Initialize Multiplication Factor to 1
        int anagram_Word_num = 1;//Initialize Multiplication Factor to 1 for String 2
        Map<Character, Integer> wordPrimeMap = wordPrimeMap();//Get the Prime numbers Mapped to each alphabets in English
        for (int i = 0; i < words_char.length; i++) {
            words_char_num *= wordPrimeMap.get(words_char[i]);//get Multiplication value for String 1
        }
        for (int i = 0; i < anagram_Word_char.length; i++) {
            anagram_Word_num *= wordPrimeMap.get(anagram_Word_char[i]);//get Multiplication value for String 2
        }

        return anagram_Word_num == words_char_num;
    }
/**
 * Get the Prime numbers Mapped to each alphabets in English
 * @return
 */
    public static Map<Character, Integer> wordPrimeMap() {
        List<Integer> primes = primes(26);
        int k = 65;
        Map<Character, Integer> map = new TreeMap<Character, Integer>();
        for (int i = 0; i < primes.size(); i++) {
            Character character = (char) k;
            map.put(character, primes.get(i));
            k++;
        }
        // System.out.println(map);
        return map;
    }
/**
 * get first N prime Numbers where Number is greater than 2
 * @param N : Number of Prime Numbers
 * @return
 */
    public static List<Integer> primes(Integer N) {
        List<Integer> primes = new ArrayList<Integer>();
        primes.add(2);
        primes.add(3);

        int n = 5;
        int k = 0;
        do {
            boolean is_prime = true;
            for (int i = 2; i <= Math.sqrt(n); i++) {
                if (n % i == 0) {
                    is_prime = false;
                    break;
                }
            }

            if (is_prime == true) {
                primes.add(n);

            }
            n++;
            // System.out.println(k);
        } while (primes.size() < N);

        // }

        return primes;
    }

}
1
Kumar Pallav

IMHO, die effizienteste Lösung wurde von @Siguza bereitgestellt. Ich habe sie erweitert, um Strings mit Leerzeichen abzudecken, z.

public int getAnagramScore(String Word, String anagram) {

        if (Word == null || anagram == null) {
            throw new NullPointerException("Both, Word and anagram, must be non-null");
        }

        char[] wordArray = Word.trim().toLowerCase().toCharArray();
        char[] anagramArray = anagram.trim().toLowerCase().toCharArray();

        int[] alphabetCountArray = new int[26];

        int reference = 'a';

        for (int i = 0; i < wordArray.length; i++) {
            if (!Character.isWhitespace(wordArray[i])) {
                alphabetCountArray[wordArray[i] - reference]++;
            }
        }
        for (int i = 0; i < anagramArray.length; i++) {
            if (!Character.isWhitespace(anagramArray[i])) {
                alphabetCountArray[anagramArray[i] - reference]--;
            }
        }

        for (int i = 0; i < 26; i++)
            if (alphabetCountArray[i] != 0)
                return 0;

        return Word.length();

    }
1

Wie ein Mathematiker über das Problem denken könnte , bevor er Code schreibt :

  1. Die Beziehung "sind Anagramme" zwischen Zeichenfolgen ist eine Äquivalenzrelation, also unterteilt sie die Menge aller Zeichenfolgen in Äquivalenzklassen.
  2. Angenommen, wir hatten die Regel, aus jeder Klasse ein Vertreter (Kinderbett) zu wählen, dann ist es einfach zu testen, ob zwei Klassen gleich sind, indem ihre Vertreter verglichen werden.
  3. Ein offensichtlicher Vertreter für eine Reihe von Zeichenfolgen ist "das kleinste Element in lexikografischer Reihenfolge", das durch Sortieren aus jedem Element leicht berechnet werden kann. Beispielsweise ist der Vertreter der Anagrammklasse, die 'hat' enthält, 'aht'.

In Ihrem Beispiel sind "Schulmeister" und "Klassenzimmer" Anagramme, da sie beide in der Anagrammklasse mit der Krippe "acehlmoorsst" sind.

Im Pseudocode:

>>> def crib(Word):
...     return sorted(Word)
...
>>> crib("schoolmaster") == crib("theclassroom")
True
1
Colonel Panic

Hier ist meine Lösung. Explodieren Sie zuerst die Zeichenketten in Char-Arrays, sortieren Sie sie und vergleichen Sie, ob sie gleich sind oder nicht. Ich denke, die Komplexität dieses Codes ist O (a + b). Wenn a = b, können wir O (2A) sagen.

public boolean isAnagram(String s1, String s2) {

        StringBuilder sb1 = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();
        if (s1.length() != s2.length())
            return false;

        char arr1[] = s1.toCharArray();
        char arr2[] = s2.toCharArray();
        Arrays.sort(arr1);
        Arrays.sort(arr2);



        for (char c : arr1) {
            sb1.append(c);
        }

        for (char c : arr2) {
            sb2.append(c);
        }

        System.out.println(sb1.toString());
        System.out.println(sb2.toString());

        if (sb1.toString().equals(sb2.toString()))
            return true;
        else
            return false;

    }

Eine ähnliche Antwort wurde möglicherweise in C++ gepostet, hier ist es wieder in Java. Beachten Sie, dass die eleganteste Methode die Verwendung der Trie ist, um die Zeichen in sortierter Reihenfolge zu speichern. Dies ist jedoch eine komplexere Lösung. Eine Möglichkeit ist, ein Hash-Set zu verwenden, um alle Wörter, die wir vergleichen, zu speichern und sie dann einzeln zu vergleichen. Um sie zu vergleichen, erstellen Sie ein Array von Zeichen mit dem Index, der den ANCII-Wert der Zeichen darstellt (unter Verwendung eines Normalizers, da der ANCII-Wert von 'a' 97 ist) und den Wert, der die Anzahl der Vorkommen dieses Zeichens darstellt. Dies wird in der Zeit O(n) ausgeführt und verwendet den O (m * z) -Raum, wobei m die Größe des aktuellenWords und z die Größe des gespeichertenWords ist, für die wir ein Char [] erstellen.

public static boolean makeAnagram(String currentWord, String storedWord){
    if(currentWord.length() != storedWord.length()) return false;//words must be same length
    Integer[] currentWordChars = new Integer[totalAlphabets];
    Integer[] storedWordChars = new Integer[totalAlphabets];
    //create a temp Arrays to compare the words
    storeWordCharacterInArray(currentWordChars, currentWord);
    storeWordCharacterInArray(storedWordChars, storedWord);
    for(int i = 0; i < totalAlphabets; i++){
        //compare the new Word to the current charList to see if anagram is possible
        if(currentWordChars[i] != storedWordChars[i]) return false;
    }
    return true;//and store this Word in the HashSet of Word in the Heap
}
//for each Word store its characters
public static void storeWordCharacterInArray(Integer[] characterList, String Word){
    char[] charCheck = Word.toCharArray();
    for(char c: charCheck){
        Character cc = c;
        int index = cc.charValue()-indexNormalizer;
        characterList[index] += 1;
    }
}
1
ak_2050

Der Sortieransatz ist nicht der beste. Es braucht O(n) Platz und O(nlogn) Zeit. Erstellen Sie stattdessen eine Hash-Map aus Zeichen und zählen Sie sie (erhöhen Sie die Zeichen, die in der ersten Zeichenfolge enthalten sind, und verringern Sie die Zeichen, die in der zweiten Zeichenfolge erscheinen). Wenn eine bestimmte Anzahl Null erreicht, entfernen Sie sie aus dem Hash. Wenn zwei Zeichenfolgen Anagramme sind, ist die Hash-Tabelle am Ende leer - ansonsten ist sie nicht leer.

Einige wichtige Hinweise: (1) Groß-/Kleinschreibung ignorieren und (2) Leerzeichen ignorieren.

Hier ist die detaillierte Analyse und Implementierung in C #: Testen, ob zwei Zeichenketten Anagramme sind

0
Zoran Horvat

Hier ist ein anderer Ansatz, der HashMap in Java verwendet

public static boolean isAnagram(String first, String second) {
    if (first == null || second == null) {
        return false;
    }
    if (first.length() != second.length()) {
        return false;
    }
    return doCheckAnagramUsingHashMap(first.toLowerCase(), second.toLowerCase());
}

private static boolean doCheckAnagramUsingHashMap(final String first, final String second) {
    Map<Character, Integer> counter = populateMap(first, second);
    return validateMap(counter);
}

private static boolean validateMap(Map<Character, Integer> counter) {
    for (int val : counter.values()) {
        if (val != 0) {
            return false;
        }
    }
    return true;
}

Hier ist der Testfall

@Test
public void anagramTest() {
    assertTrue(StringUtil.isAnagram("keep" , "PeeK"));
    assertFalse(StringUtil.isAnagram("Hello", "hell"));
    assertTrue(StringUtil.isAnagram("SiLeNt caT", "LisTen cat"));       
}
0
craftsmannadeem
// When this method returns 0 means strings are Anagram, else Not.

public static int isAnagram(String str1, String str2) {
        int value = 0;
        if (str1.length() == str2.length()) {
            for (int i = 0; i < str1.length(); i++) {
                value = value + str1.charAt(i);
                value = value - str2.charAt(i);
            }

        } else {
            value = -1;
        }
        return value;
    }
0
shiv

Die einfachste Lösung mit Komplexität O(N) verwendet Map.

public static Boolean checkAnagram(String string1, String string2) {
    Boolean anagram = true;

    Map<Character, Integer> map1 = new HashMap<>();
    Map<Character, Integer> map2 = new HashMap<>();


    char[] chars1 = string1.toCharArray();
    char[] chars2 = string2.toCharArray();

    for(int i=0; i<chars1.length; i++) {
        if(map1.get(chars1[i]) == null) {
            map1.put(chars1[i], 1);
        } else {
            map1.put(chars1[i], map1.get(chars1[i])+1);
        }

        if(map2.get(chars2[i]) == null) {
            map2.put(chars2[i], 1);
        } else {
            map2.put(chars2[i], map2.get(chars2[i])+1);
        }
    }

    Set<Map.Entry<Character, Integer>> entrySet1 = map1.entrySet();
    Set<Map.Entry<Character, Integer>> entrySet2 = map2.entrySet();
    for(Map.Entry<Character, Integer> entry:entrySet1) {

        if(entry.getValue() != map2.get(entry.getKey())) {
            anagram = false;
            break;
        }
    }

    return anagram;
}
0
chaatna

Ich habe gesehen, dass niemand den "Hashcode" -Ansatz verwendet hat, um die Anagramme herauszufinden. Ich fand meinen Ansatz etwas anders als die oben diskutierten Ansätze und dachte daher daran, ihn zu teilen. Ich habe den folgenden Code geschrieben, um die Anagramme zu finden, die in O (n) funktionieren. 

/**
 * This class performs the logic of finding anagrams
 * @author ripudam
 *
 */
public class AnagramTest {

    public static boolean isAnagram(final String Word1, final String Word2) {

            if (Word1 == null || Word2 == null || Word1.length() != Word2.length()) {
                 return false;
            }

            if (Word1.equals(Word2)) {
                return true;
            }

            final AnagramWrapper Word1Obj = new AnagramWrapper(Word1);
            final AnagramWrapper Word2Obj = new AnagramWrapper(Word2);

            if (Word1Obj.equals(Word2Obj)) {
                return true;
            }

            return false;
        }

        /*
         * Inner class to wrap the string received for anagram check to find the
         * hash
         */
        static class AnagramWrapper {
            String Word;

            public AnagramWrapper(final String Word) {
                this.Word = Word;
            }

            @Override
            public boolean equals(final Object obj) {

                return hashCode() == obj.hashCode();
            }

            @Override
            public int hashCode() {
                final char[] array = Word.toCharArray();
                int hashcode = 0;
                for (final char c : array) {
                    hashcode = hashcode + (c * c);
                }
                return hashcode;
            }
         }
    }
0
Ripu Daman

Eine einfache Methode, um herauszufinden, ob der testString ein Anagramm des baseString ist.

private static boolean isAnagram(String baseString, String testString){
    //Assume that there are no empty spaces in either string.

    if(baseString.length() != testString.length()){
        System.out.println("The 2 given words cannot be anagram since their lengths are different");
        return false;
    }
    else{
        if(baseString.length() == testString.length()){
            if(baseString.equalsIgnoreCase(testString)){
                System.out.println("The 2 given words are anagram since they are identical.");
                return true;
            }
            else{
                List<Character> list = new ArrayList<>();

                for(Character ch : baseString.toLowerCase().toCharArray()){
                    list.add(ch);
                }
                System.out.println("List is : "+ list);

                for(Character ch : testString.toLowerCase().toCharArray()){
                    if(list.contains(ch)){
                        list.remove(ch);
                    }
                }

                if(list.isEmpty()){
                    System.out.println("The 2 words are anagrams");
                    return true;
                }
            }
        }
    }
    return false;
}
0
Anshul Abhinav

Entschuldigung, die Lösung ist in C #, aber ich denke, die verschiedenen Elemente, mit denen die Lösung gefunden wird, sind ziemlich intuitiv. Ein leichter Tweak ist für Wörter mit Bindestrich erforderlich, aber für normale Wörter sollte es gut funktionieren.

    internal bool isAnagram(string input1,string input2)
    {
        Dictionary<char, int> outChars = AddToDict(input2.ToLower().Replace(" ", ""));
        input1 = input1.ToLower().Replace(" ","");
        foreach(char c in input1)
        {
            if (outChars.ContainsKey(c))
            {
                if (outChars[c] > 1)
                    outChars[c] -= 1;
                else
                    outChars.Remove(c);
            }
        }
        return outChars.Count == 0;
    }

    private Dictionary<char, int> AddToDict(string input)
    {
        Dictionary<char, int> inputChars = new Dictionary<char, int>();
        foreach(char c in input)
        {
            if(inputChars.ContainsKey(c))
            {
                inputChars[c] += 1;
            }
            else
            {
                inputChars.Add(c, 1);
            }     
        }
        return inputChars;
    }
0
Sai

Eine andere Lösung ohne zu sortieren.

public static boolean isAnagram(String s1, String s2){
    //case insensitive anagram

    StringBuffer sb = new StringBuffer(s2.toLowerCase());
    for (char c: s1.toLowerCase().toCharArray()){
        if (Character.isLetter(c)){

            int index = sb.indexOf(String.valueOf(c));
            if (index == -1){
                //char does not exist in other s2
                return false;
            }
            sb.deleteCharAt(index);
        }
    }
    for (char c: sb.toString().toCharArray()){
        //only allow whitespace as left overs
        if (!Character.isWhitespace(c)){
            return false;
        }
    }
    return true;
}
0
jmh
private static boolean checkAnagram(String s1, String s2) {
   if (s1 == null || s2 == null) {
       return false;
   } else if (s1.length() != s2.length()) {
       return false;
   }
   char[] a1 = s1.toCharArray();
   char[] a2 = s2.toCharArray();
   int length = s2.length();
   int s1Count = 0;
   int s2Count = 0;
   for (int i = 0; i < length; i++) {
       s1Count+=a1[i];
       s2Count+=a2[i];
   }
   return s2Count == s1Count ? true : false;
}
0
Amardeep Kumar