Solve google foobar staircase problem with python

Question:

Given an n number of bricks i find out how many possible different staircases can be built: each staircase must have at least 2 steps. No two steps are allowed to be at the same height – each step must be lower than the previous one. All steps must contain at least one brick. A step’s height is classified as the total amount of bricks that make up that step.
For example, when N = 5, you have 2 choice of how to build the staircase (# indicates a brick):

   # 1
#### 4

or

 ## 2
### 3

I have actually managed to solve the problem: the more obvious way was to use itertools to find all the possible combinations and then select the possible ones. However i finally figured out something like this:

def _solution(bricks, struct):
  result = 0
  for used_bricks in range(1, bricks if not struct else struct[-1]):
    elapsed_bricks = bricks - used_bricks
    result += _solution(elapsed_bricks, [*struct, used_bricks])
  if not bricks:
    # print(struct)
    result += 1
  return result

def solution(n):
  if not n:
    return 0
  return _solution(n, [])

This works, great! If i call solution(6) it returns 3 as expected, however this function-recursion method works greatly for low values of n, it took an hour to calculate n = 100, and however what i am doing is still calculating all the possible permutations. Is there a fastest way to do this?

Asked By: Giuppox

||

Answers:

it took an hour to calculate n = 100
because your solution is exponential time and for a standard machine this is expected.

each staircase must have at least 2 steps. No two steps are allowed to be at 
the same height - each step must be lower than the previous one. All steps must 
contain at least one brick 

From this we can infer that any solution staircase for some number of bricks N will be an ascending ordering of natural numbers from 1 to N-1 such that their sum is N and each number is unique.
This problem can be reduced to partition problem in which we need to find total number of partitions of N such that each partition size is unique.

Let SkN be the number of partitions of N such that each of the summands is from 1 to k.
This follows the recurrence,
SkN = Sk-1N-k + Sk-1N
Clearly answer to our problem is given by, SN-1N
Here is the solution using bottom up dynamic programming, O(N2),

def _solution(bricks):
    S = [1, *([0]*(bricks))]
    for i in range(1, bricks):  # k for our Sk(N) 
        for j in range(bricks, i-1, -1):  # N for our Sk(N)
            S[j] += S[j-i]  
    return S[bricks]

def solution(n):
  if not n or n < 3:  #2 steps min. are required which requires (1+2)=3 bricks
    return 0
  return _solution(n)
Answered By: Manav Chhibber

Here’s a recursive approach with memoization, taking i bricks from n for each recursive attempt, while making sure that i is less than the previous height by passing on i as the new height for the recursive call:

def solution(n, height=None, memo={}):
    height = height or n
    key = n, height
    if key not in memo:
        memo[key] = 3 > n < height or sum(
            solution(n - i, i) for i in range(2, min(n + 1, height)))
    return memo[key]

Demo: https://replit.com/@blhsing/Python

Answered By: blhsing
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.