Can You Find A Number Worth Its Weight In Letters?"

A FiveThirtyEight Riddler puzzle.

By Vamshi Jandhyala in mathematics Riddler

January 10, 2020

Riddler Classic

In Jewish study, “Gematria” is an alphanumeric code where words are assigned numerical values based on their letters. We can do the same in English, assigning 1 to the letter A, 2 to the letter B, and so on, up to 26 for the letter Z. The value of a word is then the sum of the values of its letters. For example, RIDDLER has an alphanumeric value of 70, since R + I + D + D + L + E + R becomes 18 + 9 + 4 + 4 + 12 + 5 + 18 = 70.

But what about the values of different numbers themselves, spelled out as words? The number 1 (ONE) has an alphanumeric value of 15 + 14 + 5 = 34, and 2 (TWO) has an alphanumeric value of 20 + 23 + 15 = 58. Both of these values are bigger than the numbers themselves.

Meanwhile, if we look at larger numbers, 1,417 (ONE THOUSAND FOUR HUNDRED SEVENTEEN) has an alphanumeric value of 379, while 3,140,275 (THREE MILLION ONE HUNDRED FORTY THOUSAND TWO HUNDRED SEVENTY FIVE) has an alphanumeric value of 718. These values are much smaller than the numbers themselves.

If we consider all the whole numbers that are less than their alphanumeric value, what is the largest of these numbers?

Solution

NUM_TO_NAME = {
0:"ZERO",
1:"ONE",
2:"TWO",
3:"THREE",
4:"FOUR",
5:"FIVE",
6:"SIX",
7:"SEVEN",
8:"EIGHT",
9:"NINE",
10:"TEN",
11:"ELEVEN",
12:"TWELVE",
13:"THIRTEEN",
14:"FOURTEEN",
15:"FIFTEEN",
16:"SIXTEEN",
17:"SEVENTEEN",
18:"EIGHTEEN",
19:"NINETEEN",
20:"TWENTY",
30:"THIRTY",
40:"FORTY",
50:"FIFTY",
60:"SIXTY",
70:"SEVENTY",
80:"EIGHTY",
90:"NINTY",
100:"HUNDRED"
}

LETTER_TO_NUM = {c:(ord(c) - ord('A')+1) for c in ("ABCDEFGHIJKLMNOPRQSTUVWXYZ")}
LETTER_TO_NUM[' '] = 0

def value(name):
    print(name)
    return sum([LETTER_TO_NUM[c] for c in name])

def num_to_name(num):
    name = None
    if num >=1 and num <=10:
       name = NUM_TO_NAME[num]
    elif num <= 100 and num % 10 == 0:
       name = NUM_TO_NAME[num]
    elif num < 100:
        name = NUM_TO_NAME[num - (num % 10)] + " " + NUM_TO_NAME[num % 10]
    elif num < 1000:
        name = NUM_TO_NAME[num // 100 ] + " HUNDRED " + num_to_name(num % 100)
    return name


print(max(n for n in range(1,500) if value(num_to_name(n))>n))