Python function to solve binomial function - python

I need a function that can solve the following: for a binomial function nCr=k, given r and k find n. in mathematics nCr=n!/r!(n-r)! I tried following but it doesn't solve it. for example 8C6=28, for my function the inputs are 6 and 28 and i want to find 8. This may not have exact integer number so I want to find an x>=n.
"""
I am approaching it this way, i.e. find the solution of a polynomial function iteratively, hope there is a better way"""
"""I am approaching it this way, i.e. find the solution of a polynomial function iteratively, hope there is a better way"""
def find_n(r,k):
#solve_for_n_in(n*(n-1)...(n-r)=math.factorial(r)*k
#in the above example solve_for_n(n*(n-1)(n-2)(n-3)(n-4)(n-5)=720*28)
sum=math.factorial(r)*k
n=r
p=1
while p<sum:
p=1
for i in range(0,r+2):
p*=(n-i+1)
n+=1
return n
Thanks.

I spot a mistake in your code.
sum=n
You're setting sum to n
then,
while sum<factorial(r)*k:
sum*=n
You're multiplying sum by n again. so now sum = n**2.
this would be better:
while sum<factorial(r)*k:
n+=1
sum*=n

This is just an idea of how this problem could be approached, while maintaining a high degree of readability.
nCr = n! / {{r!}{n-r}!} = n(n-1)...(n-r+1) / {r!}
The right hand side is some value k.
Start with n = 2*(r+1).
nCr < RHS => n is too small => increase n
nCr > RHS => n is too big => decrease n
nCr == RHS => found n
...
...
Keep doing this till you find n or something goes wrong.
import math
def find_n(r,k):
if k==1:
return r # RHS is 1 when n and r are the same
RHS = math.factorial(r) * k
possible_n = 2 * r;
possible_numerator = math.factorial(possible_n)
possible_denom = math.factorial(possible_n - r)
while True:
# current n is too small
if ( possible_numerator // possible_denom ) < RHS:
# try possible_n + 1
possible_n = possible_n + 1
possible_numerator = math.factorial(possible_n)
possible_denom = math.factorial(possible_n - r)
elif ( possible_numerator // possible_denom ) > RHS:
# try possible_n - 1
possible_n = possible_n - 1
possible_numerator = math.factorial(possible_n)
possible_denom = math.factorial(possible_n - r)
elif ( possible_n == r):
print ("***n smaller than r***");
sys.exit(0);
elif ( possible_numerator // possible_denom ) == RHS:
return possible_n
print( find_n(6, 28) ) # should print 8
print( find_n(6, 462) ) # should print 11
print( find_n(6, 3003) ) # should print 14
print( find_n(5, 3003) ) # should print 15

I used a function that calculates the binomial coefficient to implement the feature nCr
def binomial(n,k):
return 1 if k==0 else (0 if n==0 else binomial(n-1, k) + binomial(n-1, k-1))
def nCr(r,c):
n=0
b=binomial(n,r)
while b<c:
n=n+1
b=binomial(n,r)
if b==c:
return n
return None
nCr(6,28)
8

Related

Reduce time /space complexity of simple loop

So basically if i have an iteration like this in python
Ive editted the question to include my full code
class Solution:
def myPow(self, x: float, n: int) -> float:
temp = [];
span = range(1,abs(n))
if n ==0:
return 1
if abs(n)==1:
temp.append(x)
else:
for y in span:
if y == 1:
temp = []
temp.append(x*x)
else:
temp.append(temp[-1] * x)
if(n < 0):
return 1/temp[-1]
else:
return temp[-1]
The problem link is : Pow(x,n)-leetcode
How can I modify this to conserve memory and time. Is there another data structure i can use. Im just learning python....
------------EDIT------------
ive modified the code to use a variable instead of a list for the temp data
class Solution:
def myPow(self, x: float, n: int) -> float:
span = range(1,abs(n))
if n ==0:
return 1
if abs(n)==1:
temp = x
else:
for y in span:
if y == 1:
temp = x*x
else:
temp = temp * x
if(n < 0):
return 1/temp
else:
return temp
I still have a problem with my time complexity.
Its working for many testcases, however when it trys to run with x = 0.00001 and n = 2147483647. The time limit issue arises
To reduce the time complexity you can divide the work each time by taking x to the power of 2 and dividing the exponent by two. This makes a logarithmic time algorithm since the exponent is halved at each step.
Consider the following examples:
10^8 = 10^(2*4) = (10^2)^4 = (10*10)^4
Now, there is one edge case. When the exponent is an odd number you can't integer divide it by 2. So in that case you need to multiply the results by the base one additional time.
The following is a direct recursive implementation of the above idea:
class Solution:
def myPow(self, x: float, n: int) -> float:
sign = -1 if n < 0 else 1
n = abs(n)
def helper(x, n):
if n == 1: return x
if n == 0: return 1
if n % 2 == 1:
return helper(x*x, n // 2) * x
else:
return helper(x*x, n // 2)
res = helper(x, n)
if sign == -1:
return 1/res
else:
return res
Note that we have taken abs of the exponent and stored the sign and deal with it at the end.
Instead of iterating from 1 to n, use divide-and-conquer: divide the exponent by 2 and use recursion to get that power, and then square that result. If n was odd, multiply one time more with x:
class Solution:
def myPow(self, x: float, n: int) -> float:
if n == 0:
return 1
if n == 1:
return x
if n < 0:
return self.myPow(1/x, -n)
temp = self.myPow(x, n // 2)
temp *= temp
if n % 2:
temp *= x
return temp
A simple naive solution might be:
def myPow(x: float, n: int) -> float:
## -----------------------
## if we have a negative n then invert x and take the absolute value of n
## -----------------------
if n < 0:
x = 1/x
n = -n
## -----------------------
retval = 1
for _ in range(n):
retval *= x
return retval
While this technically works, you will wait until the cows come home to get a result for:
x = 0.00001 and n = 2147483647
So we need to find a shortcut. Lets' consider 2^5. Our naïve method would calculate that as:
(((2 * 2) * 2) * 2) * 2 == 32
However, what might we observe about the problem if we group some stuff together in a different way:
(2 * 2) * (2 * 2) * 2 == 32
similarly:
((2 * 2) * (2 * 2) * 2) * ((2 * 2) * (2 * 2) * 2) == 32 * 32 = 1024
We might observe that we only technically need to calculate
(2 * 2) * (2 * 2) * 2 == 32
once and use it twice to get 2^10.
Similarly we only need to calcuate:
2 * 2 = 4
once and use it twice to get 2^5....
This suggests a recursion to me.
Let's modify our first attempt to use this divide and concur method.
def myPow2(x: float, n: int) -> float:
## -----------------------
## if we have a negative n then invert x and take the absolute value of n
## -----------------------
if n < 0:
x = 1/x
n = -n
## -----------------------
## -----------------------
## We only need to calculate approximately half the work and use it twice
## at any step.
## -----------------------
def _recurse(x, n):
if n == 0:
return 1
res = _recurse(x, n//2) # calculate it once
res = res * res # use it twice
return res * x if n % 2 else res # if n is odd, multiple by x one more time (see 2^5 above)
## -----------------------
return _recurse(x, n)
Now let's try:
print(myPow2(2.0, 0))
print(myPow2(2.0, 1))
print(myPow2(2.0, 5))
print(myPow2(2.1, 3))
print(myPow2(2.0, -2))
print(myPow2(0.00001, 2147483647))
That gives me:
1
2.0
32.0
9.261000000000001
0.25
0.0
If you have to loop, you have to lope and there is nothing that can be done. Loops in python are slow. That said you may not have to loop and if you do have to loop, it may be possible to push this loop to a highly optimised internal function. Tell us what you are trying to do (not how you think you have to do it, appending elements to a lis may or may not be needed). Always recall the two rules of program optimisation General Rule: Don't do it. Rule for experts: Don't do it yet. Make it work before you make it fast, who knows, it may be fast enough.

How to tell if number can be writen as sum of n different squares?

I know how to check if the number can be represented as the sum of two squares with a brute-force approach.
def sumSquare( n) :
i = 1
while i * i <= n :
j = 1
while(j * j <= n) :
if (i * i + j * j == n) :
print(i, "^2 + ", j , "^2" )
return True
j = j + 1
i = i + 1
return False
But how to do it for n distinct positive integers. So the question would be:
Function which checks if the number can be written as sum of 'n' different squares
I have some examples.
For e.g.
is_sum_of_squares(18, 2) would be false because 18 can be written as the sum of two squares (3^2 + 3^2) but they are not distinct.
(38,3) would be true because 5^2+3^2+2^2 = 38 and 5!=3!=2.
I can't extend the if condition for more values. I think it could be done with recursion, but I have problems with it.
I found this function very useful since it finds the number of squares the number can be split into.
def findMinSquares(n):
T = [0] * (n + 1)
for i in range(n + 1):
T[i] = i
j = 1
while j * j <= i:
T[i] = min(T[i], 1 + T[i - j * j])
j += 1
return T[n]
But again I can't do it with recursion. Sadly I can't wrap my head around it. We started learning it a few weeks ago (I am in high school) and it is so different from the iterative approach.
Recursive approach:
def is_sum_of_squares(x, n, used=None):
x_sqrt = int(x**0.5)
if n == 1:
if x_sqrt**2 == x:
return used.union([x_sqrt])
return None
used = used or set()
for i in set(range(max(used, default=0)+1, int((x/n)**0.5))):
squares = is_sum_of_squares(x-i**2, n-1, used.union([i]))
if squares:
return squares
return None
Quite a compelling exercise. I have attempted solving it using recursion in a form of backtracking. Start with an empty list, run a for loop to add numbers to it from 1 to max feasible (square root of target number) and for each added number continue with recursion. Once the list reaches the required size n, validate the result. If the result is incorrect, backtrack by removing the last number.
Not sure if it is 100% correct though. In terms of speed, I tried it on the (1000,13) input and the process finished reasonably fast (3-4s).
def is_sum_of_squares(num, count):
max_num = int(num ** 0.5)
return backtrack([], num, max_num, count)
def backtrack(candidates, target, max_num, count):
"""
candidates = list of ints of max length <count>
target = sum of squares of <count> nonidentical numbers
max_num = square root of target, rounded
count = desired size of candidates list
"""
result_num = sum([x * x for x in candidates]) # calculate sum of squares
if result_num > target: # if sum exceeded target number stop recursion
return False
if len(candidates) == count: # if candidates reach desired length, check if result is valid and return result
result = result_num == target
if result: # print for result sense check, can be removed
print("Found: ", candidates)
return result
for i in range(1, max_num + 1): # cycle from 1 to max feasible number
if candidates and i <= candidates[-1]:
# for non empty list, skip numbers smaller than the last number.
# allow only ascending order to eliminate duplicates
continue
candidates.append(i) # add number to list
if backtrack(candidates, target, max_num, count): # next recursion
return True
candidates.pop() # if combination was not valid then backtrack and remove the last number
return False
assert(is_sum_of_squares(38, 3))
assert(is_sum_of_squares(30, 3))
assert(is_sum_of_squares(30, 4))
assert(is_sum_of_squares(36, 1))
assert not(is_sum_of_squares(35, 1))
assert not(is_sum_of_squares(18, 2))
assert not(is_sum_of_squares(1000, 13))

writing recursive function to compute no. of graphs

I am trying to write a code in python, to calculate the maximum graphs sets by using this formula for n vertices:
2**(n(n-1)/2) (i hope i wrote it correctly)
i am trying to do it in the lowest complexity/running time buy using % of 1000000007- is recursive the right way? or iterative?
I've read the Wikipedia article regarding exponential squaring- but couldn't make the leap from there to my problem :(
after some pen and pen and paper work I've discovered that in this case- n(n-1)/2 is always even - so i am removing the block that deals with odd n values.
This is the code a wrote so far for the recursion-
x for the base (2) and n for the number of vertices:
def graphs_num(x, n):
n = (n*n-n)/2
if n == 0:
return 0
elif n == 1:
return 1
else:
y = graphs_num(x, n/2)
return y*y
no results so far -can you assist please?
2nd edit: (i forgot the x in the last line)
here's #alec's code:
def count(n, total=1):
n = (n*n-1)/2
if n < 2:
return total
total *= 2 ** (n - 1) % 1000000007
return count(x, n-1, total)
count(4)
now I am looking to have x already defined as 2- so the only input need by the function will be n
I'm not completely familiar with this problem but based on the formula you gave this will return the same result for n >= 0 (I assume you wouldn't have a negative number of vertices).
def count(n, total=1):
if n < 2:
return total
total *= 2 ** (n - 1)
return count(n-1, total)
>>> count(5)
1024
Edit (explanation):
Basically you will notice that the values increase by a factor of 2**n.
>>> [2 ** (n * (n-1) // 2) for n in range(1, 6)]
[1, 2, 8, 64, 1024]
This can be illustrated by the following:
f(1) = 1 = 2**0
f(2) = 2 = 2**1 * 2**0
f(3) = 8 = 2**2 * 2**1 * 2**0
...
And simplified to show how it might be used recursively:
f(1) = 1 = 2**0
f(2) = 2 = 2**1 * f(1)
f(3) = 8 = 2**2 * f(2)
...
By this point, it is easy to notice the relationship is f(n) = 2**(n-1) * f(n-1). In the recursive function, the lines underneath the base case do exactly this:
total *= 2 ** (n - 1)
return count(n-1, total)
I multiple the total by 2**(n-1), and recurse to the next value for n, remembering to decrement by 1. The base case ensures we bottom out below 2, and returns the total.
Now if you want to change the base of the exponent and use a mod, it will behave accordingly.
def count(x, n, total=1):
if n < 2:
return total
total *= x ** (n - 1) % 1000000007
return count(x, n-1, total)
>>> count(2, 3)
8
>>> count(3, 3)
27

How to write 2**n - 1 as a recursive function?

I need a function that takes n and returns 2n - 1 . It sounds simple enough, but the function has to be recursive. So far I have just 2n:
def required_steps(n):
if n == 0:
return 1
return 2 * req_steps(n-1)
The exercise states: "You can assume that the parameter n is always a positive integer and greater than 0"
2**n -1 is also 1+2+4+...+2n-1 which can made into a single recursive function (without the second one to subtract 1 from the power of 2).
Hint: 1+2*(1+2*(...))
Solution below, don't look if you want to try the hint first.
This works if n is guaranteed to be greater than zero (as was actually promised in the problem statement):
def required_steps(n):
if n == 1: # changed because we need one less going down
return 1
return 1 + 2 * required_steps(n-1)
A more robust version would handle zero and negative values too:
def required_steps(n):
if n < 0:
raise ValueError("n must be non-negative")
if n == 0:
return 0
return 1 + 2 * required_steps(n-1)
(Adding a check for non-integers is left as an exercise.)
To solve a problem with a recursive approach you would have to find out how you can define the function with a given input in terms of the same function with a different input. In this case, since f(n) = 2 * f(n - 1) + 1, you can do:
def required_steps(n):
return n and 2 * required_steps(n - 1) + 1
so that:
for i in range(5):
print(required_steps(i))
outputs:
0
1
3
7
15
You can extract the really recursive part to another function
def f(n):
return required_steps(n) - 1
Or you can set a flag and define just when to subtract
def required_steps(n, sub=True):
if n == 0: return 1
return 2 * required_steps(n-1, False) - sub
>>> print(required_steps(10))
1023
Using an additional parameter for the result, r -
def required_steps (n = 0, r = 1):
if n == 0:
return r - 1
else:
return required_steps(n - 1, r * 2)
for x in range(6):
print(f"f({x}) = {required_steps(x)}")
# f(0) = 0
# f(1) = 1
# f(2) = 3
# f(3) = 7
# f(4) = 15
# f(5) = 31
You can also write it using bitwise left shift, << -
def required_steps (n = 0, r = 1):
if n == 0:
return r - 1
else:
return required_steps(n - 1, r << 1)
The output is the same
Have a placeholder to remember original value of n and then for the very first step i.e. n == N, return 2^n-1
n = 10
# constant to hold initial value of n
N = n
def required_steps(n, N):
if n == 0:
return 1
elif n == N:
return 2 * required_steps(n-1, N) - 1
return 2 * required_steps(n-1, N)
required_steps(n, N)
One way to get the offset of "-1" is to apply it in the return from the first function call using an argument with a default value, then explicitly set the offset argument to zero during the recursive calls.
def required_steps(n, offset = -1):
if n == 0:
return 1
return offset + 2 * required_steps(n-1,0)
On top of all the awesome answers given earlier, below will show its implementation with inner functions.
def outer(n):
k=n
def p(n):
if n==1:
return 2
if n==k:
return 2*p(n-1)-1
return 2*p(n-1)
return p(n)
n=5
print(outer(n))
Basically, it is assigning a global value of n to k and recursing through it with appropriate comparisons.

How to make perfect power algorithm more efficient?

I have the following code:
def isPP(n):
pos = [int(i) for i in range(n+1)]
pos = pos[2:] ##to ignore the trivial n** 1 == n case
y = []
for i in pos:
for it in pos:
if i** it == n:
y.append((i,it))
#return list((i,it))
#break
if len(y) <1:
return None
else:
return list(y[0])
Which works perfectly up until ~2000, since I'm storing far too much in memory. What can I do to make it work efficiently for large numbers (say, 50000 or 100000). I tried to make it end after finding one case, but my algorithm is still far too inefficient if the number is large.
Any tips?
A number n is a perfect power if there exists a b and e for which b^e = n. For instance 216 = 6^3 = 2^3 * 3^3 is a perfect power, but 72 = 2^3 * 3^2 is not.
The trick to determining if a number is a perfect power is to know that, if the number is a perfect power, then the exponent e must be less than log2 n, because if e is greater then 2^e will be greater than n. Further, it is only necessary to test prime es, because if a number is a perfect power to a composite exponent it will also be a perfect power to the prime factors of the composite component; for instance, 2^15 = 32768 = 32^3 = 8^5 is a perfect cube root and also a perfect fifth root.
The function isPerfectPower shown below tests each prime less than log2 n by first computing the integer root using Newton's method, then powering the result to check if it is equal to n. Auxiliary function primes compute a list of prime numbers by the Sieve of Eratosthenes, iroot computes the integer kth-root by Newton's method, and ilog computes the integer logarithm to base b by binary search.
def primes(n): # sieve of eratosthenes
i, p, ps, m = 0, 3, [2], n // 2
sieve = [True] * m
while p <= n:
if sieve[i]:
ps.append(p)
for j in range((p*p-3)/2, m, p):
sieve[j] = False
i, p = i+1, p+2
return ps
def iroot(k, n): # assume n > 0
u, s, k1 = n, n+1, k-1
while u < s:
s = u
u = (k1 * u + n // u ** k1) // k
return s
def ilog(b, n): # max e where b**e <= n
lo, blo, hi, bhi = 0, 1, 1, b
while bhi < n:
lo, blo, hi, bhi = hi, bhi, hi+hi, bhi*bhi
while 1 < (hi - lo):
mid = (lo + hi) // 2
bmid = blo * pow(b, (mid - lo))
if n < bmid: hi, bhi = mid, bmid
elif bmid < n: lo, blo = mid, bmid
else: return mid
if bhi == n: return hi
return lo
def isPerfectPower(n): # x if n == x ** y, or False
for p in primes(ilog(2,n)):
x = iroot(p, n)
if pow(x, p) == n: return x
return False
There is further discussion of the perfect power predicate at my blog.
IIRC, it's far easier to iteratively check "Does it have a square root? Does it have a cube root? Does it have a fourth root? ..." You will very quickly get to the point where putative roots have to be between 1 and 2, at which point you can stop.
I think a better way would be implementing this "hack":
import math
def isPP(n):
range = math.log(n)/math.log(2)
range = (int)(range)
result = []
for i in xrange(n):
if(i<=1):
continue
exponent = (int)(math.log(n)/math.log(i))
for j in [exponent-1, exponent, exponent+1]:
if i ** j == n:
result.append([i,j])
return result
print isPP(10000)
Result:
[[10,4],[100,2]]
The hack uses the fact that:
if log(a)/log(b) = c,
then power(b,c) = a
Since this calculation can be a bit off in floating points giving really approximate results, exponent is checked to the accuracy of +/- 1.
You can make necessary adjustments for handling corner cases like n=1, etc.
a relevant improvement would be:
import math
def isPP(n):
# first have a look at the length of n in binary representation
ln = int(math.log(n)/math.log(2)) + 1
y = []
for i in range(n+1):
if (i <= 1):
continue
# calculate max power
li = int(math.log(i)/math.log(2))
mxi = ln / li + 1
for it in range(mxi):
if (it <= 1):
continue
if i ** it == n:
y.append((i,it))
# break if you only need 1
if len(y) <1:
return None
else:
return list(y[0])

Categories

Resources