Distributing teams into units - recursion

Really struggling to solve this problem correctly.
my solution, that correctly solves some of the test cases is here:
Really hoping that someone can help me understand what's missing, or point me to solutions that I can learn from
Problem Description:
administration is considering to house each team in several units with at least 5 people per unit. A team can have from 5 to 100 members, depending on the sport they do. For example, if there are 16 team members, there are 6 ways to distribute the team members into units: (1) one unit with 16 team members; (2) two units with 5 and 11 team members, respectively; (3) two units with 6 and 10 team members, respectively; (4) two units with 7 and 9 team members, respectively; (5) two units with 8 team members each; (6) two units with 5 team members each plus a third unit with 6 team members. This list might become quite lengthy for a large team size.
In order to see how many choices to distribute the team members there are, the administration would like to have a computer program that computes for a number n the number m(n) of possible ways to distribute the team members into the units allocated, with at least 5 people per unit. Note that equivalent distributions like 5 + 5 + 6, 5 + 6 + 5 and 6 + 5 + 5 are counted only once. So m(16) = 6 (as seen above), m(17) = 7 (namely 17, 5 + 12, 6 + 11, 7 + 10, 8 + 9, 5 + 5 + 7, 5 + 6 + 6) and m(20) = 13.
The computer program should read the number n and compute m(n).

The recursion is pretty simple: We can count the partitions of n items that include the lower bound, and those that don't, and add them together. If we include the lower bound (lb), then there are n - lb more items to place, and our lower bound hasn't changed. If we're not including it, then there are still n items to place, but our lb has increased. Our base cases are simple: when the lower bound is higher than the number of items, there are no partitions. When they're equal, there is one. This code should do it:
def count (n, lb):
if (lb > n):
return 0
if (lb == n):
return 1
return count (n - lb, lb) + count (n, lb + 1)
count (20, 5) #=> 13
If you want to test different values, you can use a JS version of this:
const count = (n, lb) =>
lb > n
? 0
: lb == n
? 1
: count (n - lb, lb) + count (n, lb + 1)
console .log (count (20, 5))
And if you want to see the actual values instead of the counts, you can run this variant:
const count = (n, lb) =>
lb > n
? []
: lb == n
? [[n]]
: [
... count (n - lb, lb) .map (r => [lb, ...r]),
... count (n , lb + 1)
]
console .log (count (17, 5))

Related

Google Foobar Fuel Injection Perfection

Problem:
Fuel Injection Perfection
Commander Lambda has asked for your help to refine the automatic quantum antimatter fuel injection system for her LAMBCHOP doomsday device. It's a great chance for you to get a closer look at the LAMBCHOP - and maybe sneak in a bit of sabotage while you're at it - so you took the job gladly.
Quantum antimatter fuel comes in small pellets, which is convenient since the many moving parts of the LAMBCHOP each need to be fed fuel one pellet at a time. However, minions dump pellets in bulk into the fuel intake. You need to figure out the most efficient way to sort and shift the pellets down to a single pellet at a time.
The fuel control mechanisms have three operations:
Add one fuel pellet Remove one fuel pellet Divide the entire group of fuel pellets by 2 (due to the destructive energy released when a quantum antimatter pellet is cut in half, the safety controls will only allow this to happen if there is an even number of pellets) Write a function called solution(n) which takes a positive integer as a string and returns the minimum number of operations needed to transform the number of pellets to 1. The fuel intake control panel can only display a number up to 309 digits long, so there won't ever be more pellets than you can express in that many digits.
For example: solution(4) returns 2: 4 -> 2 -> 1 solution(15) returns 5: 15 -> 16 -> 8 -> 4 -> 2 -> 1
Test cases
Inputs: (string) n = "4" Output: (int) 2
Inputs: (string) n = "15" Output: (int) 5
my code:
def solution(n):
n = int(n)
if n == 2:
return 1
if n % 2 != 0:
return min(solution(n + 1), solution(n - 1)) + 1
else:
return solution(int(n / 2)) + 1
This is the solution that I came up with with passes 4 out of 10 of the test cases. It seems to be working fine so im wondering if it is because of the extensive runtime. I thought of applying memoization but im not sure how to do it(or if it is even possible). Any help would be greatly appreciated :)
There are several issues to consider:
First, you don't handle the n == "1" case properly (operations = 0).
Next, by default, Python has a limit of 1000 recursions. If we compute the log2 of a 309 digit number, we expect to make a minimum of 1025 divisions to reach 1. And if each of those returns an odd result, we'd need to triple that to 3075 recursive operations. So, we need to bump up Python's recursion limit.
Finally, for each of those divisions that does return an odd value, we'll be spawning two recursive division trees (+1 and -1). These trees will not only increase the number of recursions, but can also be highly redundant. Which is where memoization comes in:
import sys
from functools import lru_cache
sys.setrecursionlimit(3333) # estimated by trial and error
#lru_cache()
def solution(n):
n = int(n)
if n <= 2:
return n - 1
if n % 2 == 0:
return solution(n // 2) + 1
return min(solution(n + 1), solution(n - 1)) + 1
print(solution("4"))
print(solution("15"))
print(solution(str(10**309 - 1)))
OUTPUT
> time python3 test.py
2
5
1278
0.043u 0.010s 0:00.05 100.0% 0+0k 0+0io 0pf+0w
>
So, bottom line is handle "1", increase your recursion limit, and add memoization. Then you should be able to solve this problem easily.
There are more memory- and runtime-efficient ways to solve the problem, which is what Google is testing for with their constraints. Every time you recurse a function, you put another call on the stack, or 2 calls when you recurse twice on each function call. While they seem basic, a while loop was a lot faster for me.
Think of the number in binary - when ever you have a streak of 1s >1 in length at LSB side of the number, it makes sense to add 1 (which will flip that streak to all 0s but add another bit to the overall length), then shift right until you find another 1 in the LSB position. You can solve it in a fixed memory block in O(n) using just a while loop.
If you don't want or can't use functools, you can build your own cache this way :
cache = {}
def solution_rec(n):
n = int(n)
if n in cache:
return cache[n]
else:
if n <= 1:
return 0
if n == 2:
return 1
if n % 2 == 0:
div = n / 2
cache[div] = solution(div)
return cache[div] + 1
else:
plus = n + 1
minus = n - 1
cache[plus] = solution(n + 1)
cache[minus] = solution(n - 1)
return min(cache[plus], cache[minus]) + 1
However, even if it runs much faster and has less recursive calls, it's still too much recursive calls for Python default configuration if you test the 309 digits limit.
it works if you set sys.setrecursionlimit to 1562.
An implementation of #rreagan3's solution, with the exception that an input of 3 should lead to a subtraction rather than an addition even through 3 has a streak of 1's on the LSB side:
def solution(n):
n = int(n)
count = 0
while n > 1:
if n & 1 == 0:
n >>= 1
elif n & 2 and n != 3:
n += 1
else:
n -= 1 # can also be: n &= -2
count += 1
return count
Demo: https://replit.com/#blhsing/SlateblueVeneratedFactor

Dynamic Programming: Number of Seating Arrangements

This was the bar-raiser question at a company I recently interviewed at. The premise is, a movie theatre has to follow a distance rule where every two seated individuals must have at least six feet distance between them. We are given a list of N non-negative integers where list[k] is the distance between seat k and seat k + 1 and a single row has N+1 seats. We need to figure out the number of valid seating arrangements.
EDIT: After thinking about it more this is what I got so far
def count(seats):
# No seats then no arrangements can be made
if seats == 0:
return 0
elif seats == 1:
# 1 seat means 2 arrangements -- leave it empty (skip) or occupy it
return 2
if list[seats-1] < 6:
return count(seats - 1) + counts(seats - k(seats))
else:
return count(seats - 1)
Recall that list will contain the distance between seat i and seat i+1 so at every seat I will check if the distance between the current seat and the previous one is >= 6 or < 6. If its less than 6 then I can skip the current seat or I can occupy it. Now here's the tricky bit, if I decide to occupy the seat my subproblem is not seats - 1, it will seats - (# of seats to skip to get to the next valid seat). I'm not sure how to find this one. The other case is more trivial, where the distance between the previous seat and current is >= 6 so whether I occupy the current seat or not my subproblem, number of seats, shrinks by one.
You can use two pointer technique and dynamic programming to solve this problem.
Here dp[i] stands for the number of valid combinations where ith seat is the last one used (last -> greatest index).
Code:
def count(distances):
pref_dist = answer = 0
pos = pos_sum = pos_dist = 0
dp = [1] * (len(distances) + 1)
for i in range(len(distances)):
pref_dist += distances[i]
while(pref_dist - pos_dist >= 6):
pos_dist += distances[pos]
pos_sum += dp[pos]
pos += 1
dp[i + 1] += pos_sum
return sum(dp) + 1
Time complexity:
It is O(n) where n is the number of seats (not O(n^2)) because while condition is true at most n times in whole code execution (pointer pos never decreases, every time the condition is true then pos is increased by one and pos upper limit is n) and every operation inside it use a constant amount of time.
Examples:
Six seats and distance array [5, 2, 4, 1, 2]
count([5, 2, 4, 1, 2]) -> 16
These are the valid combinations (1 means taken):
000000 101000 000010 100001
100000 000100 100010 010001
010000 100100 010010 001001
001000 010100 000001 101001
Four seats and distance array [8, 10, 16]
count([8, 10, 6]) -> 16
Every combination is a valid combination. Four seats => 2^4 combinations.

Fill three numbers inside One number

I am trying to fit 3 numbers inside 1 number.But numbers will be only between 0 and 11.So their (base) is 12.For example i have 7,5,2 numbers.I come up with something like this:
Three numbers into One number :
7x12=84
84x5=420
420+2=422
Now getting back Three numbers from One number :
422 MOD 12 = 2 (the third number)
422 - 2 = 420
420 / 12 = 35
And i understanded that 35 is multiplication of first and the second number (i.e 7 and 5)
And now i cant get that 7 and 5 anyone knows how could i ???
(I started typing this answer before the other one got posted, but this one is more specific to Arduino then the other one, so I'm leaving it)
The code
You can use bit shifting to get multiple small numbers into one big number, in code it would look like this:
int a, b, c;
//putting then together
int big = (a << 8) + (b << 4) + c;
//separating them again
a = (big >> 8) & 15;
b = (big >> 4) & 15;
c = big & 15;
This code only works when a, b and c are all in the range [0, 15] witch appears to be enough for you case.
How it works
The >> and << operators are the bitshift operators, in short a << n shifts every bit in a by n places to the left, this is equivalent to multiplying by 2^n. Similarly, a >> n shifts to to the right. An example:
11 << 3 == 120 //0000 1011 -> 0101 1000
The & operator performs a bitwise and on the two operands:
6 & 5 == 4 // 0110
// & 0101
//-> 0100
These two operators are combined to "pack" and "unpack" the three numbers. For the packing every small number is shifted a bit to the left and they are all added together. This is how the bits of big now look (there are 16 of them because ints in Arduino are 16 bits wide):
0000aaaabbbbcccc
When unpacking, the bits are shifted to the right again, and they are bitwise anded together with 15 to filter out any excess bits. This is what that last operation looks like to get b out again:
00000000aaaabbbb //big shifted 4 bits to the right
& 0000000000001111 //anded together with 15
-> 000000000000bbbb //gives the original number b
All is working exactly like in base 10 (or 16). Here after your corrected example.
Three numbers into One number :
7x12^2=1008
5*12^1=60
2*12^0=2
1008+60+2=1070
Now getting back Three numbers from One number :
1070 MOD 12 = 2 (the third number)
1070/12 = 89 (integer division) => 89 MOD 12 = 5
89 / 12 = 7
Note also that the maximum value will be 11*12*12+11*12+11=1727.
If this is really programming related, you will be using 16bits instead of 3*8 bits so sparing one byte. An easyer method not using base 12 would be fit each number into half a byte (better code efficiency and same transmission length):
7<<(4+4) + 5<<4 + 2 = 1874
1874 & 0x000F = 2
1874>>4 & 0x000F = 5
1874>>8 & 0x0F = 7
Because MOD(12) and division by 12 is much less efficient than working with powers of 2
you can use the principle of the positional notation to change from one or the other in any base
Treat yours numbers (n0,n1,...,nm) as a digit of a big number in the base B of your choosing so the new number is
N = n0*B^0 + n1*B^1 + ... + nm*B^m
to revert the process is also simple, while your number is greater than 0 find its modulo in respect to the base to get to get the first digit, then subtracts that digit and divide for the base, repeat until finish while saving each digit along the way
digit_list = []
while N > 0 do:
d = N mod B
N = (N - d) / B
digit_list.append( d )
then if N is N = n0*B^0 + n1*B^1 + ... + nm*B^m doing N mod B give you n0, then subtract it leaving you with n1*B^1 + ... + nm*B^m and divide by B to reduce the exponents of all B and that is the new N, N = n1*B^0 + ... + nm*B^(m-1) repetition of that give you all the digit you start with
here is a working example in python
def compact_num( num_list, base=12 ):
return sum( n*pow(base,i) for i,n in enumerate(num_list) )
def decompact_num( n, base=12):
if n==0:
return [0]
result = []
while n:
n,d = divmod(n,base)
result.append(d)
return result
example
>>> compact_num([2,5,7])
1070
>>> decompact_num(1070)
[2, 5, 7]
>>> compact_num([10,2],16)
42
>>> decompact_num(42,16)
[10, 2]
>>>

Find row of pyramid based on index?

Given a pyramid like:
0
1 2
3 4 5
6 7 8 9
...
and given the index of the pyramid i where i represents the ith number of the pyramid, is there a way to find the index of the row to which the ith element belongs? (e.g. if i = 6,7,8,9, it is in the 3rd row, starting from row 0)
There's a connection between the row numbers and the triangular numbers. The nth triangular number, denoted Tn, is given by Tn = n(n-1)/2. The first couple triangular numbers are 0, 1, 3, 6, 10, 15, etc., and if you'll notice, the starts of each row are given by the nth triangular number (the fact that they come from this triangle is where this name comes from.)
So really, the goal here is to determine the largest n such that Tn ≤ i. Without doing any clever math, you could solve this in time O(√n) by just computing T0, T1, T2, etc. until you find something bigger than i. Even better, you could binary search for it in time O(log n) by computing T1, T2, T4, T8, etc. until you overshoot, then binary searching on the range you found.
Alternatively, we could try to solve for this directly. Suppose we want to find the choice of n such that
n(n + 1) / 2 = i
Expanding, we get
n2 / 2 + n / 2 = i.
Equivalently,
n2 / 2 + n / 2 - i = 0,
or, more easily:
n2 + n - 2i = 0.
Now we use the quadratic formula:
n = (-1 &pm; √(1 + 8i)) / 2
The negative root we can ignore, so the value of n we want is
n = (-1 + √(1 + 8i)) / 2.
This number won't necessarily be an integer, so to find the row you want, we just round down:
row = ⌊(-1 + √(1 + 8i)) / 2⌋.
In code:
int row = int((-1 + sqrt(1 + 8 * i)) / 2);
Let's confirm that this works by testing it out a bit. Where does 9 go? Well, we have
(-1 + √(1 + 72)) / 2 = (-1 + √73) / 2 = 3.77
Rounding down, we see it goes in row 3 - which is correct!
Trying another one, where does 55 go? Well,
(-1 + √(1 + 440)) / 2 = (√441 - 1) / 2 = 10
So it should go in row 10. The tenth triangular number is T10 = 55, so in fact, 55 starts off that row. Looks like it works!
I get row = math.floor (√(2i + 0.25) - 0.5) where i is your number
Essentially the same as the guy above but I reduced n2 + n to (n + 0.5)2 - 0.25
I think ith element belongs nth row where n is number of n(n+1)/2 <= i < (n+1)(n+2)/2
For example, if i = 6, then n = 3 because n(n+1)/2 <= 6
and if i = 8, then n = 3 because n(n+1)/2 <= 8

Number of subsets of {1,2,3,...,N} containing at least 3 consecutive elements

Suppose we have a set like {1,2,3} then there is only one way to choose 3 consecutive numbers... it's the set {1,2,3}...
For a set of {1,2,3,4} we have 3 ways: 123 234 1234
(technically these are unordered sets of numbers, but writing them consecutively helps)
f(5) ; {1,2,3,4,5} -> 8 ways: 123 1234 1235 12345 234 2345 345 1345
f(6) ; {1,2,3,4,5,6} -> 20 ways: ...
f(7) ; {1,2,3,4,5,6,7} -> 47 ways: ...
So for a given N, I can get the answer by applying brute force, and calculating all such subset having 3 or more consecutive number.
Here I am just trying to find out a pattern, a technique to get the number of all such subset for a given N.
The problem is further generalized to .....discover m consecutive number within a set of size N.
There is a bijection between this problem and "the number of N-digit binary numbers with at least three consecutive 1s in a row somewhere" (the bijection being a number is 0 if excluded in the subset, and 1 if included in the subset).
This is a known problem, and should be enough information to google for a result, if you search for number of n-digit binary strings with m consecutive 1s, the second hit is Finding all n digit binary numbers with r adjacent digits as 1
Alternatively you can just look it up as http://oeis.org/search?q=0%2C0%2C1%2C3%2C8%2C20%2C47 (based on the brute-forcing you did for the first few terms) - resulting in an explicit formula of 2^n - tribonacci(n+3), see here for an explicit formula for tribonacci numbers. It also gives a recurrence relation. The analogy given is "probability (out of 2^n) of getting at least 1 run of 3 heads within n flips of a fair coin"
I can only assume that the answer to the general problem is 2^n - Fm(n+m), where Fm is the mth n-step Fibonacci number (edit: that does seem to be the case)
This sounds like homework to me, so I'll just get you started. FoOne approach is to think of the Lowest and Highest members of the run, L and H. If the set size is N and your minimum run length is M, then for each possible position P of L, you can work out how many positions of H there are....
With a bit of python code, we can investigate this:
y = set()
def cons(li, num):
if len(li) < num:
return
if len(li) == num:
y.add(tuple([i for i in li]))
else:
y.add(tuple([i for i in li]))
cons(li[1:], num)
cons(li[:-1], num)
This solution will be quite slow (it's exponential in complexity, actually), but try it out for a few small list sizes and I think you should be able to pick up the pattern.
Not sure if you mean consecutive or not. If not, then for {1, 2, 3, 4} there are 4 possibilities: {1, 2, 3} {2, 3, 4} {1, 3, 4} {1, 2, 3, 4}
I think you can calculate the solution with N!/3! where N! = N*(N-1)(N-2)...*1.
Quick answer:
Sequences(n) = (n-1)*(n-2) / 2
Long answer:
You can do this by induction. First, I'm going to re-state the problem, because your problem statement isn't clear enough.
Rule 1: For all sets of consecutive numbers 1..n where n is 2 or more
Rule 2: Count the subsets S(n) of consecutive numbers m..m+q where q is 2 or more
S(n=3)
By inspection we find only one - 123
S(n=4)
By inspection we find 3! - 123 234 and 1234
Note that S(4) contains S(3), plus two new ones... both include the new digit 4... hmm.
S(n=5)
By inspection we find ... S(n=4) as well as 345 2345 and 12345. That's 3+3=6 total.
I think there's a pattern forming here. Let's define a new function T.
Rule 3: S(n) = S(n-1) + T(n) ... for some T.
We know that S(n) contains the digit n, and should have spotted by now that S(n) also contains (as a subcomponent) all sequences of length 3 to n that include the digit n. We know they cannot be in S(n-1) so they must be in T(n).
Rule 4: T(n) contains all sequence ending in n that are of length 3 to n.
How many sequences are in S(n)?
Let's look back at S(3) S(4) and S(5), and incorporate T(n):
S(3) = S(3)
S(4) = S(3) + T(4)
S(5) = S(4) + T(5) = S(3) + T(4) + T(5)
let's generalise:
S(n) = S(3) + T(f) for all f from 4 to n.
So how many are in a given T?
Look back at rule 5 - how many sequences does it describe?
For T(4) it describes all sequences 3 and longer ending in 4. (that's 234)
For T(5) it describes all sequences 3 and longer ending in 5. (that's 345 2345 = 2)
T count Examples
4 2 1234 234
5 3 12345 2345 345
6 4 123456 23456 3456 456
Looks awfully like T(n) is simply n-2!
So
S(6) = T(6) + T(5) + T(4) + S(3)
10 = 4 + 3 + 2 + 1
And
S(7) = 15 = 5 + 4 + 3 + 2 + 1
S(8) = 21 = 6 + 5 + 4 + 3 + 2 + 1
Turning this into a formula
What's 2 * S(8)?
42 = 6 + 5 + 4 + 3 + 2 + 1 + 1 + 2 + 3 + 4 + 5 + 6
Add each pair of biggest and smallest numbers:
42 = 7 + 7 + 7 + 7 + 7 + 7
42 = 7 * 6
But that's 2 * S(8), so
S(8) = 42/2 = 21 = 7 * 6 / 2
This generalizes:
S(n) = (n-1)*(n-2) / 2
Let's check this works:
S(3) = 2*1/2 = 1
S(4) = 3*2/2 = 3
S(5) = 4*3/2 = 6
S(6) = 5*4/2 = 10
I'm satisfied.

Resources