Sometimes,two or more people may have names that are
anagrams
of each other. Let us call a group of distinct names that are all anagrams of each other an
anagramic tuple
.
For example (Norma, Ramon, Roman) is an example of an anagramic tuple of size 3 .
In names.txt , a 46K text file containing over five-thousand first names, let the size of the largest anagramic tuple be N . Let M be the number of anagramic tuples of size N . What is the value of the product N × M ?
Details and assumption
The arrangement of the names in the tuple doesn't matter. I.e. (Tia, Tai) is the same tuple as the tuple (Tai, Tia).
All the names in an anagramic tuple are distinct.
This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try
refreshing the page, (b) enabling javascript if it is disabled on your browser and,
finally, (c)
loading the
non-javascript version of this page
. We're sorry about the hassle.
My solution relied on python's dictionary object,which is essentially a Hash Table. I am interested in other approaches to this problem,feel free to post. Mine goes as follows
All anagrams of a word have the same letters just with different arrangements so using a sorted list of the letters as a key and all its anagrams as a value we can easily solve the problem.
For example the key
('A', 'A', 'D', 'I', 'N')
is associated with the array of anagrams
['DIANA', 'NADIA', 'ADINA', 'DANIA', 'DAINA', 'NAIDA']
.
After associating each key with the array of anagrams,all that is left is to find the largest values and count how many times they occur.
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
The largest anagramic tuples found are those of size 6 .
1 2 3 4 5 |
|
There are 5 of them so the answer is 6 × 5 = 3 0 .
I was about to ask why "PEEK CLAM"... :)
Log in to reply
Probably because they are anagrams of keep clam :p
Good solution.
Great Solution!,Did it in a similar way
Here goes:
from urllib2 import urlopen
from collections import Counter
k=urlopen("https://projecteuler.net/project/names.txt").read().split(',')
l=[]
for i in k:
l+=[''.join(sorted(i))]
dic=Counter(l)
N=max(dic.values())
M=Counter(dic.values())[N]
print M*N
In Python:
names = [n.strip('"') for n in open('names.txt').read().strip().split(',')]
anatuples = {} # maps sorted string to list of names that sort to that
# add each name to its appropriate tuple
for n in names:
sn = ''.join(sorted(n))
anatuples.setdefault(sn, []).append(n)
# count size of each tuple, computing m and n as we go in one pass
m = None
n = None
for tup in anatuples.itervalues():
count = len(tup)
if n is None or count > n:
n = count
m = 1
elif count == n:
m += 1
print m*n
Can you simplify this without writing program?
Log in to reply
Sorry, I don't understand what you mean.
Log in to reply
Payal's requesting that you write some pseudocode to describe your program.
Here is what I did -
I first arranged all the alphabets in the given names in ascending order. This separated all anagramic tuples as all anagramic tuples now have the same value (because they all contain the same letters).
Then I counted and deleted the anagramic tuples and stored the size and numbers of them in variables. Then I multiplied the variables.
Here is my code -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
It took about 0.1 sec to run
I solved this problem by using C++ STL map which is useful for making array with string indices.
Since anagrams will have same composition of letters, we can use this fact to group anagrams by sorting the letters on the name.
Example: KAMI will be the same like MIKA if we sort their letters (AIKM), then they are both an anagramic tuple .
I edited the input file to fit for my code (because I don't want to make the code more complex by parsing the " and commas) by deleting the " and changing , symbol to a newline.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Output: 30
My solution in action: ideone.com/MBFE6D
This is solution in VB (Note it is not perfect one , it has alot of extra code which i was using for test purpose , if u want then you may remove it ) along with finding multiplication it also sort out all anagrams and
add it to list box , along with count , after all calculation is done , it will show multiplication at end of listbox , if u want you may remove extra code to get final compact result.
link :-
google drive
contains exe + source code
as always , if u want to use code for personal use or create tutorial then give code credits to me :D
JS Version:
function sortStr(str){
var az = str.split('').sort().join('');
return az;
}
function main(){
var r = {};
var counts = [];
for(var i=0;i<names.length;i++){
names[i] = sortStr(names[i]);
r[names[i]] = 0;
}
names.sort();
for(var c=0;c<names.length;c++){
if(names[c] == names[c+1]){
r[names[c]]++;
}
}
for(var o in r){
if( !counts[r[o]] ) counts[ r[o] ] = [];
counts[ r[o] ].push(o);
}
console.log(counts);
}
main();
My solution is in C# and too large to write here however go to the bottom of the solution to see it. I prefer readability of compactness. The general approach is to firstly write something that will read the given file and parse it so that each name is in an array. We have an array of strings which we will call names.
Next we create an array of arrays. The represents an array of tuples. Now go through names and select the first one. Store the first name into an array called tuple and delete the name from names. We now loop through names and look for names that have the same length AND are anagrams of each other. This means we will need some code to determine if two names are anagrams.
Once we find a name we will add it to tuple and delete it from the list. Remember that by deleting from the array the index of the array has shifted. Therefore decrementing the indexer before finishing the loop is a good idea.
When we have finished going through all the names with respect to our first pick we now add tuple to the array of arrays. We then pick the first element in names again and repeat the process of finding anagrams. Note that we always pick the first element as it will be deleted and shifted along anyway.
When we are finished with this process we should have an array of arrays that we can search. First we search for the array inside our array with the largest count. We denote this maxCount or N . We then search for arrays in our array that have length maxCount and denote the number M . Thus the solution to the problem is M × N .
If you have computed this correctly we should have M × N = 5 × 6 = 3 0 .
Here is my code on pastebin if anybody is interested.
Problem Loading...
Note Loading...
Set Loading...
Solution:
C++ Implementation: