콘텐츠로 건너뛰기
Home » 오일러 프로젝트 17

오일러 프로젝트 17

1부터 5까지의 숫자를 영어로쓰면 one, two, three, four, five이고 각 단어의 길이를 더하면 3+3+5+4+4+=19이므로 사용된 글자는 모두 19개입니다. 1부터 1,000까지 영어로 썼을 때는 모두 몇 개의 글자를 사용해야 할까요? 빈칸이나 하이픈은 셈에서 제외하면 단어 사이에 and는 셈에 넣습니다. 예를 들어 342를 영어로 쓰면 three hundred and forty-two가 되어서 23글자, 115 = one hundred and fifteen의 경우에는 20글자가 됩니다.

접근

숫자를 영단어로 변환하는 함수를 작성하고, 1 ~ 1,000 의 범위에 대해 이 함수를 적용한 후, 글자 수를 모두 더하면 되겠다. 영어 단어를 숫자로 변환할 때의 규칙에 대해서 정리해보자.

  1. 1,000은 “one thounsand” 가 된다.
  2. 100 단위인 “hundred”는 200, 300을 표현할 때에는 -s를 붙이지 않는다. -s를 붙이는 경우는 “hundreds of ***” 처럼 쓸 때 뿐이다.
  3. 100 단위 아래로 10, 1 단위의 값이 남아있는 경우, 중간에 “and”를 사용한다.
  4. 21, 32를 각각 “twenty one”, “thirty two”라고 표현하는 것과 달리, 1 ~ 19 까지는 하나의 개별적인 단어로 표시한다. 따라서 20이상인 수는 10으로 나눈 몫과 나머지에 따라서 10단위 단어와 1단위 단어를 결합하고, 19 이하의 수는 해당 단어만 사용하면 된다.

아래 read_number() 함수는 위 규칙을 적용하여 1,000 이하의 숫자를 영단어로 변환해준다.

def read_number(n: int) -> str:
    # 1000인 경우
    if n == 1000:
        return "onethousand"
    
    res = []
    ws1 = (". one two three four five six seven eight nine ten eleven twelve thirteen "
           "fourteen fifteen sixteen seventeen eighteen nineteen").split()
    ws2 = (". . twenty thirty forty fifty sixty seventy eighty ninety").split()

    # 100 단위
    h, n = divmod(n, 100)
    if h > 0:
        res.extend([ws1[h], "hundred", "and" if n > 0 else ""])

    # 10단위, 1단위
    if n > 19:
        t, n = divmod(n, 10)
        res.extend([ws2[t], ws1[n] if n > 0 else ""])
    else:
        res.append(ws1[n] if n > 0 else "")
    return ''.join(res)


print(read_number(239))
# "twohundredandthirtynine"

위 함수를 사용하여 1 ~ 1000 사이에 적용한 후, 글자수로 변환하고 합산하면 된다.

print(sum(len(read_number(i + 1)) for i in range(1000)))