Adam Howitt's Blog

Dec 02
2003

Pt 2: Howitt's Anagram Theory

Here is my code for the Anagram program so far:

public class Anagram {
   String initialWord;
   StringBuffer anagrams=new StringBuffer();
   
   public Anagram(String word) {
   //constructor for an anagram
      this.initialWord = word;
   }
   
   public void makeAnagram (String separator) {
   //to create an anagram call this method with the separator you wish to use
   //in the resulting StringBuffer to separate words e.g. "<br>" for web apps
      anagrams.delete(0,anagrams.length());
      makeAnagram("",this.initialWord,separator);
   }
   
   public String deleteAt(String word, int pos) {
   //this method takes a string and returns the same string less the character
   //at the position specified by the integer pos
      if (pos > 0 && pos < word.length()-1) {
         return word.substring(0,pos)+word.substring(pos+1,word.length());            
      } else {
         if (pos==0) {
            return word.substring(pos+1,word.length());            
         } else {
            if (pos == word.length()-1) {
               return word.substring(0,pos);            
            } else {
               return word;   
            }
         }
      }
   }
   
   private void makeAnagram (String wordStart, String word, String separator) {
   //this is the recursive method which actually generates the list of anagrams
   //initially wordStart is the empty string but as it loops into the code it loops over
   //all the possible word beginnings
      String wordCopy = word;
      for (int i = 0; i< word.length(); i++) {
         //hide dupes: only run this word if it is the first instance of the letter in the word
         if (word.indexOf(word.charAt(i)) == i) {
            //remove the current character from the letters to be passed to the
            //next recursion since we are adding it to the wordStart segment
            wordCopy=deleteAt(word,i);
            if (word.length() > 1) {
            //complex case - current word is longer than 1 character so the current
            //character is added to the wordStart segment
               makeAnagram(wordStart + word.charAt(i),wordCopy,separator);
            } else {
            //trivial case - word length is 1 so only 1 permutation
               if (anagrams.length() == 0) {
                  //our list shouldn't start with a list separator
                  anagrams.append(wordStart).append(word);
               } else {
                  anagrams.append(separator).append(wordStart).append(word);
               }
            }
         }
      }
   }

   public int countInstances(String word, char letter) {
   //this method determines how many copies of a specific character are in the string
      int i=0;
      while (word.indexOf(letter) >= 0) {
         word=word.substring(word.indexOf(letter)+1,word.length());
         i++;
      }
      return i;
   }
   
   public static double factorial(int x) {    
   // This method computes x!
      if (x < 0)
       return 0.0;
      double fact = 1.0;
      while(x > 1) {
       fact = fact * x;
       x = x - 1;
      }
      return fact;
}
   
   public double calcAnagram () {
   //This method uses my theory - Howitt's Anagram Theory to calculate the number
   //of unique permutations possible for the given words.
   //THEORY: UniquePermutations = factorial(word.length)
   //            divided by the product of the factorials of the count of instances of each
   //            letter in the word. e.g. aabbbc would be 6!/(2!*3!*1!) = 720/(2*6*1) = 60
      String word = this.initialWord;
      double factSum = 1;
      for (int i = 0; i< word.length(); i++) {
         if (word.indexOf(word.charAt(i)) == i) {
            factSum = factSum * factorial(countInstances(word,word.charAt(i)));
         }
      }
      return factorial(word.length())/factSum;
   }

}

Here is the code to test it:

public class TestAnagram {
   public static void main(String[] args) {
      Anagram words = new Anagram(args[0]);
      String separator;
      //if a "y" is passed as a second variable, then display the anagrams else don't
      //if a 3rd argument is supplied, it is used as the separator to display the anagrams
      if (args.length >= 2 && args[1].indexOf("y")>=0) {
         if (args.length >= 3) {
            separator = ",";
         } else {
            separator = "<BR>";
         }
         
         words.makeAnagram(separator);
         System.out.println(words.anagrams);
      }
      System.out.println(words.calcAnagram());
   }      
}

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
[Add Comment] [Subscribe to Comments]
  1. BTW, you could likely speed up your program a good bit by not doing String concatentations. Consider using the StringBuffer's append method instead. So instead of doing the following...

    String foobar = foo + bar;

    You would do the following...

    StringBuffer tmp = new StringBuffer(); tmp.append(foo); tmp.append(bar); String foobar = tmp.toString();

[Add Comment]