finding if two words are anagrams of each other

后端 未结 22 1057
隐瞒了意图╮
隐瞒了意图╮ 2020-11-27 14:51

I am looking for a method to find if two strings are anagrams of one another.

Ex: string1 - abcde
string2 - abced
Ans = true
Ex: string1 - abcde
string2 - ab         


        
相关标签:
22条回答
  • 2020-11-27 15:08

    If both strings are of equal length proceed, if not then the strings are not anagrams.

    Iterate each string while summing the ordinals of each character. If the sums are equal then the strings are anagrams.

    Example:

        public Boolean AreAnagrams(String inOne, String inTwo) {
    
            bool result = false;
    
            if(inOne.Length == inTwo.Length) {
    
                int sumOne = 0;
                int sumTwo = 0;
    
                for(int i = 0; i < inOne.Length; i++) {
    
                    sumOne += (int)inOne[i];
                    sumTwo += (int)inTwo[i];
                }
    
                result = sumOne == sumTwo;
            }
    
            return result;
        }
    
    0 讨论(0)
  • 2020-11-27 15:11

    For known (and small) sets of valid letters (e.g. ASCII) use a table with counts associated with each valid letter. First string increments counts, second string decrements counts. Finally iterate through the table to see if all counts are zero (strings are anagrams) or there are non-zero values (strings are not anagrams). Make sure to convert all characters to uppercase (or lowercase, all the same) and to ignore white space.

    For a large set of valid letters, such as Unicode, do not use table but rather use a hash table. It has O(1) time to add, query and remove and O(n) space. Letters from first string increment count, letters from second string decrement count. Count that becomes zero is removed form the hash table. Strings are anagrams if at the end hash table is empty. Alternatively, search terminates with negative result as soon as any count becomes negative.

    Here is the detailed explanation and implementation in C#: Testing If Two Strings are Anagrams

    0 讨论(0)
  • 2020-11-27 15:13

    Code to find whether two words are anagrams:

    Logic explained already in few answers and few asking for the code. This solution produce the result in O(n) time.

    This approach counts the no of occurrences of each character and store it in the respective ASCII location for each string. And then compare the two array counts. If it is not equal the given strings are not anagrams.

    public boolean isAnagram(String str1, String str2)
    {
        //To get the no of occurrences of each character and store it in their ASCII location
        int[] strCountArr1=getASCIICountArr(str1);
        int[] strCountArr2=getASCIICountArr(str2);
    
        //To Test whether the two arrays have the same count of characters. Array size 256 since ASCII 256 unique values
        for(int i=0;i<256;i++)
        {
            if(strCountArr1[i]!=strCountArr2[i])
                return false;
        }
        return true;
    }
    
    public int[] getASCIICountArr(String str)
    {
        char c;
        //Array size 256 for ASCII
        int[] strCountArr=new int[256];
        for(int i=0;i<str.length();i++)
        {
            c=str.charAt(i); 
            c=Character.toUpperCase(c);// If both the cases are considered to be the same
            strCountArr[(int)c]++; //To increment the count in the character's ASCII location
        }
        return strCountArr;
    }
    
    0 讨论(0)
  • 2020-11-27 15:14

    let's take a question: Given two strings s and t, write a function to determine if t is an anagram of s.

    For example, s = "anagram", t = "nagaram", return true. s = "rat", t = "car", return false.

    Method 1(Using HashMap ):

    public class Method1 {
    
        public static void main(String[] args) {
            String a = "protijayi";
            String b = "jayiproti";
            System.out.println(isAnagram(a, b ));// output => true
    
        }
    
        private static boolean isAnagram(String a, String b) {
            Map<Character ,Integer> map = new HashMap<>();
            for( char c : a.toCharArray()) {
                map.put(c,    map.getOrDefault(c, 0 ) + 1 );
            }
            for(char c : b.toCharArray()) {
                int count = map.getOrDefault(c, 0);
                if(count  == 0 ) {return false ; }
                else {map.put(c, count - 1 ) ; }
            }
    
            return true;
        }
    
    }
    

    Method 2 :

    public class Method2 {
    public static void main(String[] args) {
        String a = "protijayi";
        String b = "jayiproti";
    
    
        System.out.println(isAnagram(a, b));// output=> true
    }
    
    private static boolean isAnagram(String a, String b) {
    
    
        int[] alphabet = new int[26];
        for(int i = 0 ; i < a.length() ;i++) {
             alphabet[a.charAt(i) - 'a']++ ;
        }
        for (int i = 0; i < b.length(); i++) {
             alphabet[b.charAt(i) - 'a']-- ;
        }
    
        for(  int w :  alphabet ) {
             if(w != 0 ) {return false;}
        }
        return true;
    
    }
    }
    

    Method 3 :

    public class Method3 {
    public static void main(String[] args) {
        String a = "protijayi";
        String b = "jayiproti";
    
    
        System.out.println(isAnagram(a, b ));// output => true
    }
    
    private static boolean isAnagram(String a, String b) {
        char[] ca = a.toCharArray() ;
        char[] cb = b.toCharArray();
        Arrays.sort(   ca     );
    
        Arrays.sort(   cb        );
        return Arrays.equals(ca , cb );
    }
    }
    

    Method 4 :

    public class AnagramsOrNot {
        public static void main(String[] args) {
            String a = "Protijayi";
            String b = "jayiProti";
            isAnagram(a, b);
        }
    
        private static void isAnagram(String a, String b) {
            Map<Integer, Integer> map = new LinkedHashMap<>();
    
            a.codePoints().forEach(code -> map.put(code, map.getOrDefault(code, 0) + 1));
            System.out.println(map);
            b.codePoints().forEach(code -> map.put(code, map.getOrDefault(code, 0) - 1));
            System.out.println(map);
            if (map.values().contains(0)) {
                System.out.println("Anagrams");
            } else {
                System.out.println("Not Anagrams");
            }
        }
    }
    

    In Python:

    def areAnagram(a, b):
        if len(a) != len(b): return False
        count1 = [0] * 256
        count2 = [0] * 256
        for i in a:count1[ord(i)] += 1
        for i in b:count2[ord(i)] += 1
    
        for i in range(256):
            if(count1[i] != count2[i]):return False    
    
        return True
    
    
    str1 = "Giniiii"
    str2 = "Protijayi"
    print(areAnagram(str1, str2))
    

    Let's take another famous Interview Question: Group the Anagrams from a given String:

    public class GroupAnagrams {
        public static void main(String[] args) {
            String a = "Gini Gina Protijayi iGin aGin jayiProti Soudipta";
            Map<String, List<String>> map = Arrays.stream(a.split(" ")).collect(Collectors.groupingBy(GroupAnagrams::sortedString));
            System.out.println("MAP => " + map);
            map.forEach((k,v) -> System.out.println(k +" and the anagrams are =>" + v ));
            /*
             Look at the Map output:
            MAP => {Giin=[Gini, iGin], Paiijorty=[Protijayi, jayiProti], Sadioptu=[Soudipta], Gain=[Gina, aGin]}
            As we can see, there are multiple Lists. Hence, we have to use a flatMap(List::stream)
            Now, Look at the output:
            Paiijorty and the anagrams are =>[Protijayi, jayiProti]
    
            Now, look at this output:
            Sadioptu and the anagrams are =>[Soudipta]
            List contains only word. No anagrams.
            That means we have to work with map.values(). List contains all the anagrams.
    
    
            */
            String stringFromMapHavingListofLists = map.values().stream().flatMap(List::stream).collect(Collectors.joining(" "));
            System.out.println(stringFromMapHavingListofLists);
        }
    
        public static String sortedString(String a) {
            String sortedString = a.chars().sorted()
                    .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
    
            return sortedString;
    
        }
    
        /*
         * The output : Gini iGin Protijayi jayiProti Soudipta Gina aGin
         * All the anagrams are side by side.
         */
    }
    
    0 讨论(0)
  • 2020-11-27 15:15

    Using an ASCII hash-map that allows O(1) look-up for each char.

    The java example listed above is converting to lower-case that seems incomplete. I have an example in C that simply initializes a hash-map array for ASCII values to '-1'

    If string2 is different in length than string 1, no anagrams

    Else, we update the appropriate hash-map values to 0 for each char in string1 and string2

    Then for each char in string1, we update the count in hash-map. Similarily, we decrement the value of the count for each char in string2.

    The result should have values set to 0 for each char if they are anagrams. if not, some positive value set by string1 remains

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define ARRAYMAX 128
    
    #define True        1
    #define False       0
    
    int isAnagram(const char *string1, 
                const char *string2) {
    
        int str1len = strlen(string1);
        int str2len = strlen(string2);
    
        if (str1len != str2len) /* Simple string length test */
            return False;
    
        int * ascii_hashtbl = (int * ) malloc((sizeof(int) * ARRAYMAX));
        if (ascii_hashtbl == NULL) {
            fprintf(stderr, "Memory allocation failed\n");
            return -1;
        }
        memset((void *)ascii_hashtbl, -1, sizeof(int) * ARRAYMAX);
        int index = 0;
        while (index < str1len) { /* Populate hash_table for each ASCII value 
                                    in string1*/
            ascii_hashtbl[(int)string1[index]] = 0;
            ascii_hashtbl[(int)string2[index]] = 0;
            index++;
        }
        index = index - 1;
        while (index >= 0) {
            ascii_hashtbl[(int)string1[index]]++; /* Increment something */
            ascii_hashtbl[(int)string2[index]]--; /* Decrement something */
            index--;
        }
        /* Use hash_table to compare string2 */
        index = 0;
        while (index < str1len) {
            if (ascii_hashtbl[(int)string1[index]] != 0) {
                /* some char is missing in string2 from string1 */
                free(ascii_hashtbl);
                ascii_hashtbl = NULL;
                return False;
            }
            index++;
        }
        free(ascii_hashtbl);
        ascii_hashtbl = NULL;
        return True;
    }
    
    int main () {
        char array1[ARRAYMAX], array2[ARRAYMAX];
        int flag;
    
        printf("Enter the string\n");
        fgets(array1, ARRAYMAX, stdin);
        printf("Enter another string\n");
        fgets(array2, ARRAYMAX, stdin);
    
        array1[strcspn(array1, "\r\n")] = 0;
        array2[strcspn(array2, "\r\n")] = 0;
        flag = isAnagram(array1, array2);
        if (flag == 1)
            printf("%s and %s are anagrams.\n", array1, array2);
        else if (flag == 0)
            printf("%s and %s are not anagrams.\n", array1, array2);
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-27 15:18

    Get table of prime numbers, enough to map each prime to every character. So start from 1, going through line, multiply the number by the prime representing current character. Number you'll get is only depend on characters in string but not on their order, and every unique set of characters correspond to unique number, as any number may be factored in only one way. So you can just compare two numbers to say if a strings are anagrams of each other.

    Unfortunately you have to use multiple precision (arbitrary-precision) integer arithmetic to do this, or you will get overflow or rounding exceptions when using this method.
    For this you may use libraries like BigInteger, GMP, MPIR or IntX.

    Pseudocode:

    prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101}
    
    primehash(string)
        Y = 1;
        foreach character in string
            Y = Y * prime[character-'a']
    
        return Y
    
    isanagram(str1, str2)
        return primehash(str1)==primehash(str2)
    
    0 讨论(0)
提交回复
热议问题