8

How would you list words that are anagrams of each other?

I was asked this question when I applied for my current job.

orchestra can be rearranged into carthorse with all original letters used exactly once therefore the words are anagrams of each other.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
jqs
  • 169
  • 3
  • 12
  • 1
    Hey! We ask this question of every programmer we interview! You're spoiling things for us! – Jim In Texas Feb 24 '09 at 03:19
  • 2
    @Jim In Texas: The question does not spoil your interview strategy, it reveals the interview strategy to be fundamentally flawed. Like picking a mechanic based on what color overalls he has on. Leaking the knowledge to new candidates that you always select blue overalls does not spoil your strategy of mechanic picking. It reveals it as the non-strategy as flawed by the fact it can be broken by people with no knowledge of programming. – Eric Leschinski Jul 30 '13 at 20:44
  • I find it hard to picture 'people with no knowledge of programming' being able to stand up at a white board and write a program to detect anagrams. This is actually a really great initial screen question for a lot of reasons. And really, if a candidate is interested enough to have read this SO question, then that's a good thing! – Jim In Texas Jul 31 '13 at 21:27

10 Answers10

22

Put all the letters in alphabetical order in the string (sorting algorithm) and then compare the resulting string.

Błażej Michalik
  • 4,474
  • 40
  • 55
Adam Davis
  • 91,931
  • 60
  • 264
  • 330
  • 1
    Yep, that's pretty much what I came up with... Got the job too! – jqs Feb 06 '09 at 21:03
  • There's an alternative algorithm involving counting the characters in each word. It's faster, but it'll be more expensive for Unicode words. – Franci Penov Feb 06 '09 at 21:42
  • I had considered that, but then you have to compare the resulting letter count arrays, hashes, or otherwise - for short anagrams my algorithm is likely faster, but for larger anagrams chances are good yours would be faster. Would be an interesting test... – Adam Davis Feb 06 '09 at 21:50
  • You wouldn't need to compare all the maps - just get one map for the first word and then for all the others see if they _match_ the same map, i.e. iterate their letters and decrement them in a copy of the map. In the end you have found all the letters and the map counts must be zeroed. – Daniel Daranas Feb 10 '09 at 13:28
  • I understand what you're saying. But the map has 26 positions. Once you've done the increment/decrement you have to go through 26 comparisons to 0 to verify the map matches. I'd have to do more research to find out which method requires more comparisons - although comparisons to 0 are cheaper... – Adam Davis Feb 10 '09 at 16:39
  • I think that method may be faster than a sorting and string comparisons as I consider it more... Maybe I'll have to do those tests... – Adam Davis Feb 10 '09 at 16:42
  • Especially if you cast the array as integers before comparing to 0 - then you've only got 7 integer comparisons, or 4 if you're on a 64 bit machine. – Adam Davis Feb 10 '09 at 16:44
  • How would this solve "Slot machines" => "Cash lost in 'em"? Isn't it valid anagram? – dotNet Decoder Jun 07 '17 at 22:10
10

Good thing we all live in the C# reality of in-place sorting of short words on quad core machines with oozles of memory. :-)

However, if you happen to be memory constrained and can't touch the original data and you know that those words contain characters from the lower half of the ASCII table, you could go for a different algorithm that counts the occurrence of each letter in each word instead of sorting.

You could also opt for that algorithm if you want to do it in O(N) and don't care about the memory usage (a counter for each Unicode char can be quite expensive).

Franci Penov
  • 74,861
  • 18
  • 132
  • 169
6

Sort each element (removing whitespace) and compare against the previous. If they are all the same, they're all anagrams.

Serafina Brocious
  • 30,433
  • 12
  • 89
  • 114
  • punctuation I can understand, for words with an apostrohphe, but spaces? I don't know many words with spaces in them... I think for the sake of a simple exercise like this you can safely assume that the words contain only letters. – ninesided Feb 06 '09 at 21:02
  • 1
    When presented as puzzles, anagrams are often spread over whole phrases. So you write the routine to be robust. – dmckee --- ex-moderator kitten Feb 07 '09 at 00:45
3

Interestingly enough, Eric Lippert's Fabulous Adventures In Coding Blog dealt with a variation on this very problem on February 4, 2009 in this post.

Grant Wagner
  • 25,263
  • 7
  • 54
  • 64
  • Dead link, archive.org to the rescue: https://web.archive.org/web/20190119000458/https://blogs.msdn.microsoft.com/ericlippert/2009/02/04/a-nasality-talisman-for-the-sultana-analyst/ – Deebster Apr 08 '20 at 18:06
2

Well Sort the words in the list.

if abc, bca, cab, cba are the inputs, then the sorted list will be abc, abc, abc, abc.

Now all of their Hash codes are equal. Compare the HashCodes.

Sandeep
  • 7,156
  • 12
  • 45
  • 57
2

The following algorithm should work:

  1. Sort the letters in each word.

  2. Sort the sorted lists of letters in each list.

  3. Compare each element in each list for equality.

Yes - that Jake.
  • 16,725
  • 14
  • 70
  • 96
  • Once the lists of letters are sorted you could compare the first to the last instead of comparing each one. If the first is the same as the last, then they are all equal. – Eric Ness Feb 06 '09 at 22:03
  • @EricNess Are you sure about that? Consider the input: "abbc" and "abcc". Same length, same first and last characters... Or perhaps I misunderstood your comment. – levigroker Feb 17 '14 at 21:52
1

Sort the letters and compare (letter by letter, string compare, ...) is the first things that comes to mind.

Austin Salonen
  • 49,173
  • 15
  • 109
  • 139
0
public static void main(String[] args) {

    String s= "abc";
    String s1="cba";



     char[] aArr = s.toLowerCase().toCharArray(); 
     char[] bArr = s1.toLowerCase().toCharArray();

  // An array to hold the number of occurrences of each character
  int[] counts = new int[26]; 

  for (int i = 0; i < aArr.length; i++){
   counts[aArr[i]-97]++;  // Increment the count of the character at respective position
   counts[bArr[i]-97]--;  // Decrement the count of the character at respective position
  }

  // If the strings are anagrams, then counts array will be full of zeros not otherwise
  for (int i = 0; i<26; i++){
   if (counts[i] != 0)
    return false;
  } 
anshulkatta
  • 2,044
  • 22
  • 30
0

Tried hashcode logic for anagram gives me false output

public static Boolean anagramLogic(String s,String s2){
    char[] ch1 = s.toLowerCase().toCharArray();
        Arrays.sort(ch1);
        char[] ch2= s2.toLowerCase().toCharArray();
        Arrays.sort(ch2);
        return ch1.toString().hashCode()==ch2.toString().hashCode(); //wrong
    }

to rectify this code, below is the only option I see,appreciate any recommendations

char[] ch1 = s.toLowerCase().toCharArray();
        Arrays.sort(ch1);
        char[] ch2= s2.toLowerCase().toCharArray();
        Arrays.sort(ch2);
        return Arrays.equals(ch1,ch2);
    }
Krish
  • 724
  • 7
  • 17
0
  1. compare length (if not equal, not a chance)
  2. make a bit vector of the length of the strings
  3. for each char in the first string find occurrences of it in the second
  4. set the bit for the first unset occurrence
  5. if you can find one stop with fail
BCS
  • 75,627
  • 68
  • 187
  • 294