Chapter 159
Can You Unravel These Number Strings?
Riddler Express
Six numbers are given in sequence: . What is the next number?
The Riddler, FiveThirtyEight, August 18, 2017(original post)
Solution
This is the look-and-say sequence: each term describes its predecessor digit by digit, by reading aloud the consecutive runs as “ copies of ”.
Apply the rule to the sixth term:
A standing fact about this sequence (due to John Conway): consecutive terms grow by a constant factor in the limit, namely Conway’s constant , the only positive real root of a degree- polynomial. The sequence never contains a digit other than , , or once those are the only digits that appear (Conway’s “cosmological theorem”), so the look-and-say can never trigger itself into using a or larger.
The computation
Encode the look-and-say rule directly: walk the string, count each run, emit “count digit” pairs. Apply seven times from the seed and check the seventh iterate.
Start with the string “”.
To advance: scan the current string left to right, finding maximal runs of equal digits.
For each run of copies of digit , emit the two-digit pair .
Iterate.
def look_and_say(s):
out = []
i = 0
while i < len(s):
j = i
while j < len(s) and s[j] == s[i]:
j += 1
out.append(str(j - i))
out.append(s[i])
i = j
return "".join(out)
s = "1"
for _ in range(6):
s = look_and_say(s)
print(s) # 13112221
# match against the six given terms plus our answer
seq = ["1"]
for _ in range(6):
seq.append(look_and_say(seq[-1]))
print(seq)
# ['1', '11', '21', '1211', '111221', '312211', '13112221']
The seventh iterate is , agreeing with the boxed answer.
Riddler Classic
Take the self-referential string where each digit (ignoring spaces) gives the count of consecutive s before the next . The first digit, , says there are three s before the first ; the second digit, , says there are three s between the first and second s; and so on. What is the limiting ratio of s to s in the infinite string?
The Riddler, FiveThirtyEight, August 18, 2017(original post)
Solution
Define a recursive construction. Generation is the single digit “”. Generation is obtained from generation by replacing each digit using the rule it imposes on the string: a in generation says “three s follow before a ”, so it expands to the block ; a in generation says “two s before a ”, so it expands to . Each expansion contributes one (the terminating one), and either three or two s.
Let and denote the count of s and s in generation . The expansion rule gives the linear recursion Each generation digit produces exactly one in the next generation (the explicit terminator of its block), giving the recursion; and a contributes three s while a contributes two, giving the recursion.
Let . Dividing the two recursions, This is a Möbius (linear-fractional) iteration. Its fixed points satisfy , that is , i.e., . The positive root is The other root is irrelevant since counts are positive. The map has derivative ; at the positive fixed point this is , which is less than in absolute value, so the fixed point is an attractor and from any positive start.
The infinite string is the limit of these generations (each generation is a strict prefix of the next), so the overall ratio of s to s is
The computation
Iterate the actual substitution rule on strings: start with “”, and at each step replace every by and every by . Confirm that the empirical ratio converges to .
Seed with the single character “”.
At each step, build the next-generation string by concatenating for each and for each .
Track counts of s and s and form the ratio.
import math
s = "3"
for n in range(1, 12):
s = "".join("3332" if c == "3" else "332" for c in s)
t, w = s.count("3"), s.count("2")
print(n + 1, t, w, round(t / w, 6))
# generation 12 ratio prints ~2.732050
print("target:", 1 + math.sqrt(3)) # 2.732050807568877
By generation the empirical matches to six decimals.