Project Euler: Problem 17

https://projecteuler.net/problem=17

If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.

If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?

NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage.

First write a number_to_words(n) function that takes an integer n between 1 and 1000 inclusive and returns a list of words for the number as described above


In [64]:
def number_to_words(n):
    """Given a number n between 1-1000 inclusive return a list of words for the number."""
    num19 = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",\
            "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", \
            "eighteen", "nineteen"]
    numTens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty",\
              "ninety"]
    # other important words: hundred, and
    hunds = n // 100
    tens = (n - hunds*100) // 10
    ones = (n - hunds*100 - tens*10)
    if n == 0:
        return("zero")
    elif n <= 19:
        return(num19[n])
    elif n < 100:
        return(numTens[tens]+num19[ones]) 
    elif n == 1000:
        return("onethousand")
    else: # n >= 100
        if n % 100 == 0:
            return(num19[hunds]+"hundred")
        elif tens <= 1:
            i = n - hunds*100
            return(num19[hunds]+"hundredand"+num19[i])
        else:
            return(num19[hunds]+"hundredand"+numTens[tens]+num19[ones])

In [65]:
number_to_words(1000)


Out[65]:
'onethousand'

Now write a set of assert tests for your number_to_words function that verifies that it is working as expected.


In [22]:
assert number_to_words(343) == ['three', 'four', 'three']
assert number_to_words(3) == ['three']
assert number_to_words(23) == ['two', 'three']

In [ ]:
assert True # use this for grading the number_to_words tests.

Now define a count_letters(n) that returns the number of letters used to write out the words for all of the the numbers 1 to n inclusive.


In [60]:
def count_letters(n):
    """Count the number of letters used to write out the words for 1-n inclusive."""
    words = [number_to_words(i) for i in range(1,n)]
    counts = [len(w) for w in words]
    return(sum(counts))

Now write a set of assert tests for your count_letters function that verifies that it is working as expected.


In [63]:
assert count_letters(6) == 19
assert count_letters(15) == 67

In [ ]:
assert True # use this for grading the count_letters tests.

Finally used your count_letters function to solve the original question.


In [66]:
count_letters(1001)


Out[66]:
21124

In [ ]:
assert True # use this for gradig the answer to the original question.