Problem 22 — Names Scores

solved Thu, 10 Oct 2019, 11:49 · level 0 · difficulty 2% projecteuler.net github

Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.

For example, when the list is sorted into alphabetical order, COLIN, which is worth $3 + 15 + 12 + 9 + 14 = 53$, is the $938$th name in the list. So, COLIN would obtain a score of $938 \times 53 = 49714$.

What is the total of all the name scores in the file?


Problem Analysis

This problem contains no number theory, recursion, or combinatorics. It is a pure data-processing exercise: the answer is a weighted sum where the weight of each name is its rank after sorting. The "alphabetical value" of a name is the sum of the 1-based positions of its letters in the alphabet (A=1, B=2, ..., Z=26), and the "name score" multiplies that value by the name's 1-based position in the sorted list. The final answer sums every name's score. The single insight that makes the problem tractable is recognising its shape: it is a classic map-reduce pipeline - parse the input, sort it, map each element to a score, and reduce the scores to a sum.

The complexity is dominated by the sort, which runs in O(n log n) time for n names (here n is roughly 5,000). The scoring pass is O(n * L) where L is the average name length, which is small and constant in practice. With n this small the entire computation finishes in well under a millisecond in C and a few milliseconds in Python, so no clever optimisation is warranted - the goal is simply a clean, correct implementation.

Solution Approach

Algorithm 0 - Parse, Sort, Score, Sum (Python and C)

Both solutions implement the same four-step pipeline and differ only in language mechanics.

Step 1 - Parse. The file is a single line of comma-separated, double-quoted tokens such as "AARON","ABBEY",.... In Python I read the whole file and call .split(",") to obtain a list of raw tokens (quotes still attached). In C I read the file into one buffer and use strtok with "," as the delimiter to split in place. Before tokenising in C, I make a single linear pass counting commas so I can allocate the char **names pointer array exactly once - one cheap scan avoids any dynamic regrowth.

Step 2 - Sort. Python's sorted() uses Timsort, a stable O(n log n) sort. In C I call qsort with a comparator that dereferences the char ** arguments and calls strcmp. A subtle but important point: every token still carries its surrounding double-quotes at this stage. Because all tokens begin with the same quote character, the quotes contribute equally to every comparison and cancel out - the sort order is identical to sorting the bare names, so no preprocessing is required before the sort.

Step 3 - Score. I iterate over the sorted list with a 1-based index. The helper word_to_num sums each letter's alphabet position using ord(c) - 64 (Python) or *c - 64 (C), skipping the quote and space characters. Since ASCII 'A' is 65, subtracting 64 maps 'A' to 1 directly - no lookup table needed.

Step 4 - Sum. Each name's value is multiplied by its rank and accumulated. The C version uses a long long accumulator: the total is around 8.7 x 10^8, which fits in a 32-bit signed integer, but I use 64-bit to remove any doubt about overflow. Python integers are arbitrary precision, so the concern does not arise.

workbench

Test cases

categoryinputanswer
main file_url = https://projecteuler.net/resources/documents/0022_names.txt 871198282

Results

solutioncategoryanswerverdict avg seconds cavg seconds py
p0022_s0 main 871198282 correct 0.000720 (63) 0.003663 (63)

Files

Tags & blogs

Blogs