오일러 프로젝트의 22번 문제는 특정한 문자열을 정해진 규칙에 따라 점수로 환원하고 그 합계를 계산하는 것이다.
여기 5천개 이상의 영문 이름들이 들어있는 46KB짜리 텍스트 파일 names.txt 이 있습니다 (우클릭해서 다운로드 받으세요). 이제 각 이름에 대해서 아래와 같은 방법으로 점수를 매기고자 합니다. 먼저 모든 이름을 알파벳 순으로 정렬합니다. 각 이름에 대해서, 그 이름을 이루는 알파벳에 해당하는 숫자(A=1, B=2, …, Z=26)를 모두 더합니다. 여기에 이 이름의 순번을 곱합니다. 예를 들어 “COLIN”의 경우, 알파벳에 해당하는 숫자는 3, 15, 12, 9, 14이므로 합이 53, 그리고 정렬했을 때 938번째에 오므로 최종 점수는 938 × 53 = 49714가 됩니다. names.txt에 들어있는 모든 이름의 점수를 계산해서 더하면 얼마입니까? ::
http://euler.synap.co.kr/prob_detail.php?id=21
접근 및 풀이
모든 글자는 대문자이며, 알파벳 글자 순서에 따라 각 글자는 점수값을 갖는다. 이를 위해서 ABCD.....Z
에 이르는 문자열에 각 점수를 대입한 사전을 만들어서 글자의 점수를 구해도 되고, 아니면 ord()
함수를 이용하는 방법도 있다. ‘A’의 아스키코드가 65이므로 ord(x) - 64
를 통해서 특정 알파벳의 점수값을 알 수 있다.
사실 문제 자체는 엄청 간단한 내용이라, 그외에 따로 코멘트 할 일은 없을 듯 하고, 여기서는 파일을 다운로드 하지 않고 http로 액세스해서 값을 계산하는 코드를 작성했다. (Python 3.6)
from urllib.request import urlopen
with urlopen('http://euler.synap.co.kr/files/names.txt') as f:
names = sorted(x.strip('"') for x in f.read().decode().split(','))
print(sum((sum(ord(c) - 64 for c in word)) * (i+1)\
for i, word in enumerate(names)))
보너스 : Swift 풀이
// Swift 4
import Foundation
main: do {
guard let url = URL(string: "http://synap.euler.co.kr/files/names.txt"),
let contents = try? String(contentsOf: url, encoding: .utf8)
else { break main }
let names = contents.split(separator: ",").sorted{ $0 < $1 }
var result = 0
for (i, word) in names.enumerated() {
result += getScore(word) * (i + 1)
}
print(result)
}
func getScore(_ s: String) -> Int {
let score = s.utf8.map{ (x) -> Int in
let y = Int(x)
return (65...91) ~= y ? y - 64 : 0
}
return score.reduce(0, +)
}
참고로 문자열 타입의 split(separator:)
는 Swift4에서 추가된 API이며, Xcode8.3 이하에서는 Foundation 내에 정의된 components(separatedBy:_)
를 사용하면 된다.