#112 - Bouncy numbers
Working from left-to-right if no digit is exceeded by the digit to its left it is called an increasing number; for example, 134468.
Similarly if no digit is exceeded by the digit to its right it is called a decreasing number; for example, 66420.
We shall call a positive integer that is neither increasing nor decreasing a “bouncy” number; for example, 155349.
Clearly there cannot be any bouncy numbers below one-hundred, but just over half of the numbers below one-thousand (525) are bouncy. In fact, the least number for which the proportion of bouncy numbers first reaches 50% is 538.
Surprisingly, bouncy numbers become more and more common and by the time we reach 21780 the proportion of bouncy numbers is equal to 90%.
Find the least number for which the proportion of bouncy numbers is exactly 99%.
We can do a brute force check to see if a number is bouncy. We can scan the number left to right, and find the first pair of numbers which does not follow the bouncy characteristic. In this way, we have a “fast-fail” approach where we don’t have to search the whole number if it’s bouncy.
For example, 155349 is bouncy. The first two digits are “15”, and since $5>1$, all digits after that should be non-decreasing. However, “53” violates this, thus the number is bouncy. We will start from 21780, and count up until we reach a proportion of 99\%.
# file: "problem112.py"
def isBouncy(x):
# Convert to list of digits
digits = [int(d) for d in str(x)]
# Find the first distinct pair
# and set whether the number should
# be increasing or decreasing.
i = 0
while i < len(digits) - 1 and digits[i] == digits[i+1]:
i += 1
# If we've reached the end, then
# all numbers are the same, so
# it's not bouncy
if i == len(digits) - 1:
return False
# Otherwise, find the direction
if digits[i + 1] < digits[i]:
increasing = False
else:
increasing = True
# Now starting from the next pair,
# see if the condition holds
i += 1
while i < len(digits) - 1:
if (digits[i + 1] < digits[i] and increasing) or \
(digits[i + 1] > digits[i] and not increasing):
return True
i += 1
return False
bouncyNums = 21780 * 9 / 10
n = 21780
while bouncyNums / n < 0.99:
n += 1
if isBouncy(n):
bouncyNums += 1
print('First reaches 99% at n =', n)
Running this short loop, we get
First reaches 99% at n = 1587000
4.4108225 seconds.
Thus, 1587000 is the first number which results in 99\% bouncy numbers below it.