Count and Say
Term 1 is "1"; each next term reads the previous aloud ("1211" → one 1, one 2, two 1s → "111221"). Return term n.
Intuition
Pure run-length encoding applied n−1 times: scan the current string, group equal consecutive digits, and emit count+digit for each run. There's no closed form — simulate.
A simulation problem — there's no closed form, so the work is reading the spec exactly and running it n−1 times. The only real decision is how to group consecutive equal characters; a language's run-length grouping (groupby here) removes the manual counter and the off-by-one that comes with it.
Approach
Describe one string
Walk with a run pointer: count how many times the current char repeats, append str(count) + char, jump past the run.
Iterate n−1 times
Start from "1" and re-describe. Strings roughly grow ~30% per step (Conway's constant λ ≈ 1.304).
Groupby shortcut
itertools.groupby does the run detection declaratively — same complexity.
Solution & live demo
Common pitfalls
Looping n times instead of n − 1
for _ in range(n):
s = ...s = "1"
for _ in range(n - 1):
s = ...The sequence starts at "1" for n = 1, so that term is the seed, not a computed step. Running the loop n times returns the (n+1)-th term.
Emitting digit-then-count
s = "".join(d + str(len(list(g))) for d, g in groupby(s))
s = "".join(str(len(list(g))) + d for d, g in groupby(s))
The rule is "say how many, then say which" — "21" means one 2 followed by one 1, giving "1211". Reversing the pair produces a different sequence entirely.
Counting all occurrences rather than consecutive runs
from collections import Counter counts = Counter(s)
for d, g in groupby(s):
...Counter collapses non-adjacent duplicates: "1211" would report three 1s, but the run-length reading is one 1, one 2, two 1s. Only consecutive equal characters form a group.
Edge cases
Loop runs zero times → "1".
Can't happen — no three equal consecutive digits ever appear in the sequence, and counts stay single-digit.