如何检查两个单词是否是anagrams
我有一个程序,告诉你两个词是否是彼此的字谜。 有几个例子可能无法正常工作,我希望有任何帮助,但是如果不是先进的,那将会很棒,因为我是第一年的程序员。 “校长”和“课堂”是互不相关的,但是当我把“课堂”改成“课堂”的时候,他们仍然说是字谜,我做错了什么?
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; } }
最快的algorithm是把每个26个英文字符映射到一个唯一的素数。 然后计算string的乘积。 根据算术的基本定理,当且仅当它们的乘积相同时,2个string是anagrams。
如果两个单词包含相同数量的字符和相同的字符,则这两个单词是彼此的字形。 您只需按字典顺序对字符进行sorting,然后比较在所有步骤中,stringa是否等于stringb。
这是一个代码示例。 看看API中的Arrays
,了解这里发生了什么。
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); }
如果对任一数组进行sorting,则解决scheme将变为O(n log n)。 但如果你使用HashMap,它是O(n)。 testing和工作。
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;
这是一个简单快速的O(n)解决scheme,不使用sorting或多个循环或哈希映射。 我们递增第一个数组中每个字符的计数,并减less第二个数组中每个字符的计数。 如果得到的计数数组满了零,则string是字符。 可以通过增加counts数组的大小来扩展以包含其他字符。
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])); } }
许多人提出了解决scheme,但我只想谈谈一些常见方法的algorithm复杂性:
-
简单的“使用
Arrays.sort()
sorting字符”的方法将是O(N log N)
。 -
如果使用基数sorting,则使用
O(M)
空间减less到O(N)
,其中M
是字母表中不同字符的数量。 (英文是26,但是理论上我们应该考虑多语言字典)。 -
使用计数数组的“计数字符”也是
O(N)
…并且比基数sorting更快,因为您不需要重新构build已sorting的string。 空间使用将是O(M)
。 -
使用字典,散列表,树形图或等价物的“计数字符”将比数组方法更慢,除非字母表很大。
-
不幸的是,在最坏的情况下,
O(N^2)
的优雅的“素数乘积”方法是这样的,这是因为对于足够长的单词或短语来说,素数的乘积不会long
。 这意味着你需要使用BigInteger
,并且用一个小常量乘以BigInteger
N倍是O(N^2)
。对于一个假设的大字母,比例因子将会很大。 把
BigInteger
作为素数的最坏情况的空间使用是(我认为)O(N*logM)
。 -
如果单词不是字谜,基于
hashcode
的方法通常是O(N)
。 如果hashcodes是相等的,那么你仍然需要做一个适当的anagramtesting。 所以这不是一个完整的解决scheme。
O(n)解决scheme,没有任何种类的sorting和使用只有一个地图。
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; }
而不是通用的解决scheme,但更快一点。 你必须在这里放置你的字母:
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; }
我们走了两个等长的string,并跟踪它们之间的差异。 我们不在乎分歧是什么,我们只是想知道他们是否有相同的字符。 我们可以在O(n / 2)中做这个,不需要任何后期处理(或许多素数)。
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 } }
是的,这个代码是依赖于小写字母的ASCII英文字符集,但不应该很难修改为其他语言。 你总是可以使用一个Map [Character,Int]来跟踪相同的信息,它会慢一些。
这里有很多复杂的答案 基于接受的答案和提到'ac' – 'bb'问题的评论,假设A = 1 B = 2 C = 3,我们可以简单地使用代表一个char的每个整数的平方并解决问题:
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; }
/* * 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; //} } }
我是C ++开发人员,下面的代码是用C ++编写的。 我相信最快和最简单的方法将是以下几点:
创build一个大小为26的整数vector,将所有槽初始化为0,并将该string的每个字符放入vector中的适当位置。 请记住,vector是按字母顺序排列的,所以如果string中的第一个字母是z,它会在myvector [26]中出现。 注意:这可以使用ASCII字符来完成,所以本质上你的代码看起来像这样:
string s = zadg; for(int i =0; i < s.size(); ++i){ myvector[s[i] - 'a'] = myvector['s[i] - 'a'] + 1; }
所以插入所有的元素将花费O(n)的时间,因为你只能遍历列表一次。 你现在可以做第二个string完全相同的事情,这也将花费O(n)的时间。 然后可以通过检查每个插槽中的计数器是否相同来比较两个vector。 如果是这样,那就意味着你在这两个string中都有相同数量的每个字符,因此它们是字形。 这两个向量的比较也应该花费O(n)的时间,因为你只能遍历一次。
注意:代码仅适用于单个字符的单词。 如果你有空格,数字和符号,你可以创build一个大小为96(ASCII字符为32-127)的向量,而不是说 – 'a',你会说 – '',因为空格字符是第一个ASCII字符列表。
我希望有帮助。 如果我在某个地方犯了一个错误,请留下评论。
通过使用更多的内存(最多N / 2个元素的HashMap),我们不需要对string进行sorting。
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; } }
这个函数实际上是运行在O(N)…而不是O(NlogN)的sortingstring的解决scheme。 如果我假设你将只使用字母字符,那么我只能使用一个26个整数的数组(从a到z没有重音或装饰)而不是hashmap。
如果我们定义:N = | one | + | two | 我们对N进行一次迭代(一次超过一次,增加计数器,一次减less两次)。 然后检查我们在mose N / 2上迭代的总数。
所描述的其他algorithm有一个优点:假设Arrays.sort使用就地版本的QuickSort或合并sorting,他们不使用额外的内存。 但是因为我们谈论的是一些字谜,我会假定我们正在谈论人类语言,所以说话不应该太长,以免给人留下记忆的问题。
类似的答案可能已经发布在C ++中,这里又是Java。 请注意,最优雅的方法是使用Trie按sorting顺序存储字符,但这是一个更复杂的解决scheme。 一种方法是使用哈希集来存储我们正在比较的所有单词,然后逐一比较它们。 为了比较它们,使用代表字符ANCII值的索引(使用标准化程序,即'a'的ANCII值为97)和表示该字符出现次数的值来制作字符数组。 这将在O(n)时间运行并使用O(m * z)空间,其中m是当前字的大小,z是存储字的大小,为此我们创build一个Char []。
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; } }
在编写任何代码之前,math家如何考虑这个问题:
- string之间的关系“anagrams”是一个等价关系 ,因此将所有string的集合划分为等价类。
- 假设我们有一个select每个class级的代表 (婴儿床)的规则,那么通过比较两个class级的代表是很容易的。
- 一组string的一个明显的代表是“ 按字典顺序排列的最小元素 ”,通过sorting可以很容易地从任何元素进行计算。 例如,包含“帽子”的anagram类的代表就是“aht”。
在你的例子中,“校长”和“课堂”是anagrams,因为他们都在婴儿床“acehlmoorsst”的字谜类。
在伪代码中:
>>> def crib(word): ... return sorted(word) ... >>> crib("schoolmaster") == crib("theclassroom") True
感谢您提出意见,同时发表评论,我发现有不正确的逻辑。 我纠正了逻辑并为每一段代码添加了评论。
// 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; }
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; } }
一些其他解决scheme没有sorting
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; }
sorting方法不是最好的。 它需要O(n)空间和O(nlogn)时间。 取而代之的是,制作一个字符散列图并对它们进行计数(增加出现在第一个string中的字符数和减less出现在第二个string中的字符数)。 当一些计数达到零时,将其从哈希中删除。 最后,如果两个string是anagrams,那么哈希表最后将是空的 – 否则它将不会是空的。
几个重要的注意事项:(1)忽略信箱和(2)忽略空格。
下面是C#中的详细分析和实现: testing如果两个string是Anagrams
一个简单的方法来确定是否testString是一个baseString的anagram。
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; }
对不起,这个解决scheme是用C#编写的,但是我认为用于解决问题的不同元素非常直观。 轻微的调整需要连字,但对于正常的话,它应该工作正常。
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; }
我看到没有人使用“散列码”的方法来找出字谜。 我发现我的方法与上面讨论的方法有些不同,因此想到分享它。 我写了下面的代码来find在O(n)中工作的字典。
/** * 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; } } }
我知道这是一个古老的问题。 However, I'm hoping this can be of help to someone. The time complexity of this solution is O(n^2).
public boolean areAnagrams(final String word1, final String word2) { if (word1.length() != word2.length()) return false; if (word1.equals(word2)) return true; if (word1.length() == 0 && word2.length() == 0) return true; String secondWord = word2; for (int i = 0; i < word1.length(); i++) { if (secondWord.indexOf(word1.charAt(i)) == -1) return false; secondWord = secondWord.replaceFirst(word1.charAt(i) + "", ""); } if (secondWord.length() > 0) return false; return true; }
Here is another approach using HashMap in Java
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; }
Here is the test case
@Test public void anagramTest() { assertTrue(StringUtil.isAnagram("keep" , "PeeK")); assertFalse(StringUtil.isAnagram("Hello", "hell")); assertTrue(StringUtil.isAnagram("SiLeNt caT", "LisTen cat")); }
So far all proposed solutions work with separate char
items, not code points. I'd like to propose two solutions to properly handle surrogate pairs as well (those are characters from U+10000 to U+10FFFF , composed of two char
items).
1) One-line O(n logn) solution which utilizes Java 8 CharSequence.codePoints()
stream:
static boolean areAnagrams(CharSequence a, CharSequence b) { return Arrays.equals(a.codePoints().sorted().toArray(), b.codePoints().sorted().toArray()); }
2) Less elegant O(n) solution (in fact, it will be faster only for long strings with low chances to be anagrams) :
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; }
I had written this program in java. I think this might also help:
public class Anagram { public static void main(String[] args) { checkAnagram("listen", "silent"); } public static void checkAnagram(String str1, String str2) { boolean isAnagram = false; str1 = sortStr(str1); str2 = sortStr(str2); if (str1.equals(str2)) { isAnagram = true; } if (isAnagram) { System.out.println("Two strings are anagram"); } else { System.out.println("Two string are not anagram"); } } public static String sortStr(String str) { char[] strArr = str.toCharArray(); for (int i = 0; i < str.length(); i++) { for (int j = i + 1; j < str.length(); j++) { if (strArr[i] > strArr[j]) { char temp = strArr[i]; strArr[i] = strArr[j]; strArr[j] = temp; } } } String output = String.valueOf(strArr); return output; } }
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; }
IMHO, the most efficient solution was provided by @Siguza, I have extended it to cover strings with space eg: "William Shakespeare", "I am a weakish speller", "School master", "The classroom"
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(); }
Here is my solution.First explode the strings into char arrays then sort them and then comparing if they are equal or not. I guess time complexity of this code is O(a+b).if a=b we can say O(2A)
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; }
You should use something like that:
for (int i...) { isFound = false; for (int j...) { if (...) { ... isFound = true; } }
Default value for isFound
should be false. Just it
A way to solve this – based on Sai Kiran's answer..
import java.util.Scanner; public class Anagram { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("Enter first word : "); String word1 = sc.nextLine(); System.out.print("Enter second word : "); String word2 = sc.nextLine(); sc.close(); System.out.println("Is Anagram : " + isAnagram(word1, word2)); } private static boolean isAnagram(String word1, String word2) { if (word1.length() != word2.length()) { System.err.println("Words length didn't match!"); return false; } char ch1, ch2; int len = word1.length(), sumOfWord1Chars = 0, sumOfWord2Chars = 0; for (int i = 0; i < len; i++) { ch1 = word1.charAt(i); if (word2.indexOf(ch1) < 0) { System.err.println("'" + ch1 + "' not found in \"" + word2 + "\""); return false; } sumOfWord1Chars += word1.charAt(i); ch2 = word2.charAt(i); if (word1.indexOf(ch2) < 0) { System.err.println("'" + ch2 + "' not found in \"" + word1 + "\""); return false; } sumOfWord2Chars += word2.charAt(i); } if (sumOfWord1Chars != sumOfWord2Chars) { System.err .println("Sum of both words didn't match, ie, words having same characters but with different counts!"); return false; } return true; } }
Works perfectly! But not a good approach because it runs in O(n^2)
boolean isAnagram(String A, String B) { if(A.length() != B.length()) return false; A = A.toLowerCase(); B = B.toLowerCase(); for(int i = 0; i < A.length(); i++){ boolean found = false; for(int j = 0; j < B.length(); j++){ if(A.charAt(i) == B.charAt(j)){ found = true; break; } } if(!found){ return false; } } for(int i = 0; i < B.length(); i++){ boolean found = false; for(int j = 0; j < A.length(); j++){ if(A.charAt(j) == B.charAt(i)){ found = true; break; } } if(!found){ return false; } } int sum1 = 0, sum2 = 0; for(int i = 0; i < A.length(); i++){ sum1 += (int)A.charAt(i); sum2 += (int)B.charAt(i); } if(sum1 == sum2){ return true; } return false; }