Beautiful strings

Today I found an interesting challenge on CodeEval – it’s from Facebook Hacker Cup 2013 Hackathon. At first I had my issues with understanding the task. Here’s the description:

[readolog_blockquote ]Given a string s, little Johnny defined the beauty of the string as the sum of the beauty of the letters in it. The beauty of each letter is an integer between 1 and 26, inclusive, and no two letters have the same beauty. Johnny doesn’t care about whether letters are uppercase or lowercase, so that doesn’t affect the beauty of a letter. (Uppercase ‘F’ is exactly as beautiful as lowercase ‘f’, for example.)

You’re a student writing a report on the youth of this famous hacker. You found the string that Johnny considered most beautiful. What is the maximum possible beauty of this string?[/readolog_blockquote]

Your input are few lines of senseless strings. Output should be a number, a sum of values for every letter. In other words this challenge can be described as following:

[readolog_blockquote ]Count encounters of every letter. Since you can use every number only once and your goal is to produce the biggest possible sum you should assign the bigger numbers to letters, which occur most often.[/readolog_blockquote]

If there are letters with same presence amount it makes no difference to which you assign the exact number. Let’s say you have three ‘a’, three ‘b’ and three ‘c’. If you decrease your assignment by one each time it won’t matter to which exact letter you’ll assign exact number, since the math is 3*26 + 3*25 + 3*24 and it doesn’t care to which letter ‘belongs’ the number ‘3’.

So here is my code. I’m sure it can be done in a one-liner, however I wouldn’t consider this challenge as trivial, therefore I’m a bit proud of my solution.

def largestHashKey(hash)
  hash.max_by{|k,v| v}
end

def letter?(lookAhead)
  lookAhead =~ /[[:alpha:]]/
end

File.open("beautifulStrings.txt").each_line do |line|
	charFrequency = Hash.new {0}
	line.split("").each do |char|
		if letter?char then charFrequency[char.downcase] +=1 end
	end
	# Now iterate through all hash values, find maximum, assign 26 to it, then maximum-1, assign 25 to it and so on

	i = largestHashKey(charFrequency)[1]
	sum = 0
	stringValue = 26

	while i>0
		if charFrequency.key(i)
			charFrequency.each_value do |value|
				if value == i
					sum += i*stringValue
					stringValue -= 1
				end
			end
		end
		i -=1
	end
	puts sum
end