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%.

#### Your Task

Complete the bouncyRatio function.

The input will be the target ratio.

The output should be the smallest number such that the proportion of bouncy numbers reaches the target ratio.

You should throw an Error for a ratio less than 0% or greater than 99%.

**Source**

  - https://projecteuler.net/problem=112
  
**Updates**

  - 26/10/2015: Added a higher precision test case.

Difficulty: introductory

Starter code:

def bouncy_ratio(percent):
	

Solutions:
from operator import lt, gt

memo = {}
is_bouncy = lambda s: memo[s] if s in memo else memo.setdefault(s, any(map(lt, s[:-1], s[1:])) and any(map(gt, s[:-1], s[1:])))

def bouncy_ratio(percent):
    if not 0 < percent < 1: raise Exception("Wrong percentage: {}".format(percent))
    x, y = 100, 0
    while y < x*percent:
        x, y = x+1, y+is_bouncy(str(x+1))
    return x

def bouncy_ratio(percent):
    is_bouncy = lambda n: any(a < b for a, b in zip(n, n[1:])) \
                        and any(a > b for a, b in zip(n, n[1:]))
    n, bouncy = 99, 0
    while bouncy < percent * n:
        n += 1
        bouncy += is_bouncy(str(n))
    return n

def bouncy_ratio(percent):
  if percent <= 0 or percent >= 99: raise
  bouncy, i = 0, 99
  while float(bouncy) / i < percent:
    i += 1
    bouncy += sum(any(f(a, b) for a, b in zip(str(i), str(i)[1:])) for f in [lambda x, y: x > y, lambda x, y: x < y]) == 2
  return i

def bouncy_ratio(target):
    bouncy = 0.0
    n = 100
    
    while bouncy / n < target:
        n += 1
        s = list(str(n))
        s_ = sorted(s)
        if s != s_ and s != s_[::-1]:
            bouncy += 1
    
    return n

def bouncy_ratio(percent):
    ans = 0
    for i in range(1, 10**10):
        s = str(i)
        res = ''.join(['=' if a == b else '>' if int(a) > int(b) else '<' for a, b in zip(s, s[1:])])
        ans += ('<' in res) and ('>' in res)
        if ans / i >= percent:
            return i

def bouncy_ratio(percent):
    b=0
    n=1
    while(True):
        s=list(str(n))
        if s!=sorted(s) and s!=sorted(s)[::-1]:
            b+=1
        if float(b)/n>=percent:
            break
        n+=1
    return n

memo = {}

def bouncy_ratio(percent):
    if not (0 <= percent <= 0.99): raise ValueError
    b, n = 0.0, 100
    while b / n < percent: 
        n += 1
        if is_bouncy(n): b += 1
    return n

def is_bouncy(n): 
    if n in memo: return memo[n]
    s = str(n)
    memo[n] = list(s) != sorted(s) and list(s) != sorted(s, reverse = True)
    
    return memo[n]

def bouncy_ratio(percent):
    if percent < 0 or percent > 0.99:
        raise Error
    n = 99
    bouncy = 0.0
    while True:
        n += 1
        ns = str(n)
        gaps = [int(ns[i]) - int(ns[i - 1]) for i in range(1, len(ns))]
        if not(all(gap >= 0 for gap in gaps) or all(gap <= 0 for gap in gaps)):
            bouncy += 1.0
            if bouncy / n >= percent:
                return n

def bouncy_ratio(percent):
    #if percent < 0.1 or percent > 0.9: raise ValueError()
    def check(i):
        d = [int(x) for x in str(i)]
        up, down = False, False
        for k in range(1, len(d)):
            if d[k] > d[k-1]: up = True
            if d[k] < d[k-1]: down = True
        return up and down
    bouncy = 0.0
    for n in range(100, 100000):
        if check(n): bouncy += 1
        if bouncy / n >= percent: return n