python recursion combination [duplicate] - python

This question already has answers here:
Understanding recursion [closed]
(20 answers)
Closed 5 months ago.
How can I write a function that computes:
C(n,k)= 1 if k=0
0 if n<k
C(n-1,k-1)+C(n-1,k) otherwise
So far I have:
def choose(n,k):
if k==0:
return 1
elif n<k:
return 0
else:

Assuming the missing operands in your question are subtraction operators (thanks lejlot), this should be the answer:
def choose(n,k):
if k==0:
return 1
elif n<k:
return 0
else:
return choose(n-1, k-1) + choose(n-1, k)
Note that on most Python systems, the max depth or recursion limit is only 1000. After that it will raise an Exception. You may need to get around that by converting this recursive function to an iterative one instead.
Here's an example iterative function that uses a stack to mimic recursion, while avoiding Python's maximum recursion limit:
def choose_iterative(n, k):
stack = []
stack.append((n, k))
combinations = 0
while len(stack):
n, k = stack.pop()
if k == 0:
combinations += 1
elif n<k:
combinations += 0 #or just replace this line with `pass`
else:
stack.append((n-1, k))
stack.append((n-1, k-1))
return combinations

Improving from Exponential to Linear time
All of the answers given so far run in exponential time O(2n). However, it's possible to make this run in O(k) by changing a single line of code.
Explanation:
The reason for the exponential running time is that each recursion separates the problem into overlapping subproblems with this line of code (see Ideone here):
def choose(n, k):
...
return choose(n-1, k-1) + choose(n-1, k)
To see why this is so bad consider the example of choose(500, 2). The numeric value of 500 choose 2 is 500*499/2; however, using the recursion above it takes 250499 recursive calls to compute that. Obviously this is overkill since only 3 operations are needed.
To improve this to linear time all you need to do is choose a different recursion which does not split into two subproblems (there are many on wikipedia).
For example the following recursion is equivalent, but only uses 3 recursive calls to compute choose(500,2) (see Ideone here):
def choose(n,k):
...
return ((n + 1 - k)/k)*choose(n, k-1)
The reason for the improvement is that each recursion has only one subproblem that reduces k by 1 with each call. This means that we are guaranteed that this recursion will only take k + 1 recursions or O(k). That's a vast improvement for changing a single line of code!
If you want to take this a step further, you could take advantage of the symmetry in "n choose k" to ensure that k <= n/2 (see Ideone here):
def choose(n,k):
...
k = k if k <= n/2 else n - k # if k > n/2 it's equivalent to k - n
return ((n + 1 - k)/k)*choose(n, k-1)

Solution from wikipedia (http://en.wikipedia.org/wiki/Binomial_coefficient)
def choose(n, k):
if k < 0 or k > n:
return 0
if k > n - k: # take advantage of symmetry
k = n - k
if k == 0 or n <= 1:
return 1
return choose(n-1, k) + choose(n-1, k-1)

You're trying to calculate the number of options to choose k out of n elements:
def choose(n,k):
if k == 0:
return 1 # there's only one option to choose zero items out of n
elif n < k:
return 0 # there's no way to choose k of n when k > n
else:
# The recursion: you can do either
# 1. choose the n-th element and then the rest k-1 out of n-1
# 2. or choose all the k elements out of n-1 (not choose the n-th element)
return choose(n-1, k-1) + choose(n-1, k)

just like this
def choose(n,k):
if k==0:
return 1
elif n<k:
return 0
else:
return choose(n-1,k-1)+choose(n-1,k)
EDIT
It is the easy way, for an efficient one take a look at wikipedia and spencerlyon2 answer

Related

How to turn this memoized recursive solution into a 'bottom-up' iterative one?

I have a solution to a problem that uses dynamic programming. I need help turning this from a recursive solution into an iterative one.
The function takes in a number and follows the three rules:
it may divide the number in half
it may subtract one
it may add one
until the number is 1. My goal is to find the minimum number of steps it takes to do this.
Here is my solution:
def solution(n):
n = int(n)
memo = {}
return memoized_fuel_injection_perfection(n, memo)
def memoized_fuel_injection_perfection(n, memo):
if n == 1:
return 0
if n == 2:
return 1
if n in memo:
return memo[n]
if n % 2 == 0:
if n not in memo:
memo[n] = memoized_fuel_injection_perfection(n//2, memo) + 1
return memo[n]
return min(memoized_fuel_injection_perfection(n-1, memo), memoized_fuel_injection_perfection(n+1, memo)) + 1
But when I input numbers larger than 300 digits long, I am getting a recursive error. How can I turn this into an iterative solution? Any help or guidance is appreciated.
Here is an iterative solution I created, but I am getting MemoryError with very large inputs. Is there some way I can optimize storing the variables so I don't have to compute them for every number?
def solution(n):
memo = {}
memo[0] = 0
memo[1] = 0
memo[2] = 1
n = int(n)
for i in range(3, n+1):
if i % 2 == 0:
memo[i] = memo[i//2] + 1
else:
memo[i] = min(memo[i//2], memo[i//2 + 1]) + 2
return memo[n]
The problem you said you're having with writing an iterative solution is the use of memoized_fuel_injection_perfection(n+1, memo), which makes it tricky to determine what order to compute results in. The key is that you cannot repeatedly go down this code path indefinitely. If you could, even your recursive solution would be invalid.
Immediately after a +1 or -1 operation, you always perform a divide-by-2. We can fuse the +1 or -1 with the divide-by-2, producing an operation that cannot increase the number. The core of an iterative solution would then look like this:
if n % 2 == 0:
table[n] = table[n//2] + 1
else:
table[n] = min(table[n//2], table[n//2+1]) + 2
Can you complete things from there? (You'll need a way to avoid computing results for every positive integer less than n.)
Here's my attempt:
def solution(n):
def is_even(n): # helper function
return n % 2 == 0
possible_nodes = {1} # 1 is the destination
consider = [n] # stack: numbers to be considered
while consider: # as long as non-empty
x = consider.pop() # now think about where can we move from x
if x in possible_nodes: # if it is already handled before
continue
if is_even(x): # if even, we just halve it
consider.append(x//2)
else: # otherwise, -1 or +1
consider += [x-1, x+1]
possible_nodes.add(x) # mark x as 'considered'
steps = {1: 0} # dict to store min steps
for x in filter(is_even, sorted(possible_nodes)): # odds calculated only when needed
if x//2 not in steps: # if x//2 was not computed, x//2 must be odd
steps[x//2] = min(steps[x//2 - 1], steps[x//2 + 1]) + 1
steps[x] = steps[x//2] + 1
return steps[n] if is_even(n) or n == 1 else min(steps[n-1], steps[n+1]) + 1
n = 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003333000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003483983333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
print(solution(n)) # 2467
print(*(solution(i) for i in range(1, 21)))
# 0 1 2 2 3 3 4 3 4 4 5 4 5 5 5 4 5 5 6 5
The code basically consists of two steps. In the first step, it enumerates all the possible steps from n, under the rule that for x,
if x is even, we only consider x//2 as the next step; this strategy is adopted also in your code;
if x is odd, we consider x-1 and x+1 as the next step.
I did this because calculating the minimum steps for all values up to n is wasteful. (Actually at first I tried to do so by initiating something like [None] * n, but it seems like python cannot handle such a long list. Even if it can, I guess that would be extremely slow.)
The next step is calculating the minimum steps, starting from the smallest number. I address the problem of accessingsteps[x+1] by "not calculating steps[x] for odd x eagerly." We only calculate steps[x] for even x eagerly, but lazily for odd x.
The rationale is the following; by the time odd x is needed, it must be the case that x is either k//2 - 1 or k//2 + 1 for some even k, which must be larger than x + 1. Since x + 1 is even, step[x+1] must have been already calculated, by the construction of the for loop.

Time out on a problem with a dynamic algorithm

I am working on an algorithmic problem:
https://leetcode.com/problems/integer-replacement/
Given a positive integer n, you can apply one of the following operations:
If n is even, replace n with n / 2.
If n is odd, replace n with either n + 1 or n - 1.
Return the minimum number of operations needed for n to become 1.
I decided to utilize an iterative dynamic programming approach, so I created a dictionary to keep track of optimal solutions to all overlapping subproblems.
This is my code:
class Solution:
def integerReplacement(self, n: int) -> int:
dic = {1:0}
for i in range(2, n+1):
#print(i)
if i % 2 == 0:
dic[i] = dic[i/2]+1
else:
dic[i] = min((dic[(i+1)/2]),(dic[(i-1)/2]))+2
#print(f"dic[{i}] is {dic[i]}")
return dic[n]
I passes 19 cases, but times out on 100000000 input (and 1 time it said that too much space was being used).
So, my question is:
Is my dynamic programming implementation flawed, or is it simply not the way to go in this case?
Thank you
This problem could be solved in O(log(n)) time complexity with O(1) space complexity.
That's why they are providing large inputs. So, your code couldn't be an optimal choice.
Now, How to solve it:
1. if n is even just divide it by 2.
2. if n is odd:
(a) if (n-1)//2 results in a number divisible by 2 then this is optimal. But with one edge case i.e.3 then you have to choose (n-1) operation because after division you can reach your target i.e. 1.
(b) else n+1 operation because (n+1)//2 will result in a number divisible by 2.
Here is the code that will pass all the test cases:
class Solution:
def integerReplacement(self, n: int) -> int:
operation = 0
while(n > 1):
operation = operation + 1
if(n%2 == 1):
if( ((n-1)//2)%2 == 0 or (n-1)//2 == 1):
n = n - 1
else:
n = n + 1
else:
n = n//2
return operation

Python Pure recursion - Divisor - One input

What is the recursive call (or inductive steps) for a function that returns the number of integers from 1 to N, which evenly divide N. The idea is to concieve a pure recursive code in python for this function. No 'for' or 'while' loops, neither modules can be used. The function num_of_divisors(42) returns 8, representing 1, 2, 3, 6, 7, 14, 21, and 42 as divisors of 42.
def num_of_divisors(n):
return sum(1 if n % i==0 else 0 for i in range(((n+1)**0.5)//1)
Good luck explaining it to your teacher!
If you really can't use for loops (?????????) then this is impossible without simulating one.
def stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num=1):
"""I had to copy this from Stack Overflow because it's such an
inane restriction it's actually harmful to learning the language
"""
if loop_num <= (n+1) ** 0.5:
if n % loop_num == 0:
return 2 + \
stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num+1)
else:
return stupid_num_of_divisors_assigned_by_shortsighted_teacher(n, loop_num+1)
else:
if n % loop_num == 0:
return 1
Bonus points: explain why you're adding 2 in the first conditional, but only 1 in the second conditional!
Here you go buddy your teacher'll be happy.
def _num_of_divisors(n, k):
if (k == 0):
return 0
return _num_of_divisors(n, k-1) + (n % k == 0)
def num_of_divisors(n):
return _num_of_divisors(n, n)
It's easier than you think to convert such a simple problem from a loop to a recursive function.
Start with a loop implementation:
n = 42
result = []
for i in range(n+1):
if n % i == 0:
result.append(i)
then write a function
def num_of_divisors_helper(i, n, result):
if <condition when a number should be added to result>:
result.append(n)
# Termination condition
if <when should it stop>:
return
# Recursion
num_of_divisors_helper(i+1, n, result)
Then you define a wrapper function num_of_divisors that calls num_of_divisors_helper. You should be able to fill the gaps in the recursive function and write the wrapper function yourself.
It's a simple, inefficient solution, but it matches your terms.
Without using %
def is_divisible(n, i, k):
if k > n:
return False
if n - i*k == 0:
return True
else:
return is_divisible(n, i, k+1)
def num_of_divisors(n, i=1):
if i > n/2:
return 1
if is_divisible(n, i, 1):
return 1 + num_of_divisors(n, i+1)
else:
return num_of_divisors(n, i+1)
num_of_divisors(42) -> 8
def n_divisors(n,t=1):
return (not n%t)+(n_divisors(n,t+1) if t < n else 0)
good luck on the test later ... better hit those books for real, go to class and take notes...
with just one input i guess
t=0
def n_divisors(n):
global t
t += 1
return (not n%t)+(n_divisors(n) if t < n else 0)

Python quickselect sorting [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 8 years ago.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Improve this question
The program is supposed to use quick select and return the median of a set of integer values.
Question: When I run the program, it tells me that k is not defined. How should I define k to get the median?
def quickSelect(lines,k):
if len(lines)!=0:
pivot=lines[(len(lines)//2)]
smallerlist=[]
for i in lines:
if i<pivot:
smallerlist.append(i)
largerlist=[]
for i in lines:
if i>pivot:
largerlist.append(i)
m=len(smallerlist)
count=len(lines)-len(smallerlist)-len(largerlist)
if k >= m and k<m + count:
return pivot
elif m > k:
return quickSelect(smallerList,k)
else:
return quickSelect(largerList, k - m - count)
The code seems to be working fine, after a minor correction.
smallerlist and largerlist had a typo.
elif m > k:
return quickSelect(smallerList,k)
else:
return quickSelect(largerList, k - m - count)
should be changed by
elif m > k:
return quickSelect(smallerlist,k)
else:
return quickSelect(largerlist, k - m - count)
This is the final corrected code, which runs just fine.
def quickSelect(lines,k):
if len(lines)!=0:
pivot=lines[(len(lines)//2)]
smallerlist=[]
for i in lines:
if i<pivot:
smallerlist.append(i)
largerlist=[]
for i in lines:
if i>pivot:
largerlist.append(i)
m=len(smallerlist)
count=len(lines)-len(smallerlist)-len(largerlist)
if k >= m and k<m + count:
return pivot
elif m > k:
return quickSelect(smallerlist,k)
else:
return quickSelect(largerlist, k - m - count)
Hope it helps
You misreported the error; it doesn't complain about k, it complains about smallerList because you defined smallerlist (lower-case-l) and then tried to call it with an uppercase-L. Python variables are case-sensitive, ie smallerlist is smallerList == False.
Looking at your code:
def quickSelect(lines, k):
if len(lines) != 0:
len(lst) != 0 is non-idiomatic; PEP-8 says it should just be lst, as in if lst:. Also, camelCase is unPythonic; your function name should be quick_select. lines implies you can only operate on text, but your function should work just as well on any orderable data type, so items would be more accurate. You should have a docstring so the next person to come along has some idea what it does, and we're going to call len(items) again, so we may as well do it once and store the result. Finally, what if k > len(items)?
def quick_select(items, k):
"""
Return the k-from-smallest item in items
Assumes 0 <= k < len(items)
"""
num_items = len(items)
if 0 <= k < num_items:
pivot = items[num_items // 2]
continuing:
smallerlist = []
for i in lines:
if i<pivot:
smallerlist.append(i)
largerlist=[]
for i in lines:
if i>pivot:
largerlist.append(i)
You've iterated through lines twice; you could combine this into a single pass. Also, better variable names:
smaller, larger = [], []
for item in items:
if item < pivot:
smaller.append(item)
elif item > pivot:
larger.append(item)
continuing with better variable names,
num_smaller = len(smaller)
num_pivot = num_items - num_smaller - len(larger)
then your ifs are out of order; they are easier to read in order, so
if k < num_smaller:
return quick_select(smaller, k)
elif k < num_smaller + num_pivot
return pivot
else:
return quick_select(larger, k - num_smaller - num_pivot)
then what if k < 0 or k >= num_items?:
else:
raise ValueError("k={} is out of range".format(k))
Finally, because this function is tail-recursive, it is easy to convert to an iterative function instead:
while True:
pivot = items[num_items // 2]
# ...
if k < num_smaller:
items = smaller
num_items = num_smaller
elif k < num_smaller + num_pivot
return pivot
else:
items = larger
num_items = num_larger
k -= num_smaller + num_pivot
... some assembly required, hope that helps!
You need to initializing k for the first time into the function. It should be the position of the item you are looking for (if the list was sorted). Default it to half the list length, for median. Call it like so:
k = len(lines) // 2
x = quickSelect(lines, k)
or if you only ever want the median, you could fix the function so you don't have to provide the index of the item you want
def quickSelect(lines, k=None):
if k is None:
k = len(lines)//2
As Hugh pointed out, this function will only select an element of the list. For a median of an even number of elements, the median should actually be the mean of the middle two elements.

Python prime number code running slow

I am trying to solve the problem mentioned here: https://www.spoj.pl/problems/PRIME1/
I am also giving the description below.
Peter wants to generate some prime numbers for his cryptosystem. Help him! Your task is to generate all prime numbers between two given numbers!
Input
The input begins with the number t of test cases in a single line (t<=10). In each of the next t lines there are two numbers m and n (1 <= m <= n <= 1000000000, n-m<=100000) separated by a space.
Output
For every test case print all prime numbers p such that m <= p <= n, one number per line, test cases separated by an empty line.`
My code is as below. I am thinking remove method on list is very slow.
import sys
import math
num = int(sys.stdin.readline());
indices = []
maxrange = 2
while(num > 0):
a,b = sys.stdin.readline().split(" ");
a = int(a)
b = int(b)
if(a < 2):
a = 2
indices.append((a,b))
if(b > maxrange):
maxrange= b
num = num - 1
val = int(math.sqrt(maxrange)+1)
val2 = int(math.sqrt(val)+1)
checks = range(2,val2)
for i in range(2,val2):
for j in checks:
if(i!= j and j%i == 0):
checks.remove(j)
primes = range(2,val)
for i in checks:
for j in primes:
if(i != j and j%i == 0):
primes.remove(j)
primes2 = range(2,maxrange)
for i in primes:
for j in primes2:
if(j != i and j%i == 0):
primes2.remove(j)
for (a,b) in indices:
for p in primes2:
if(a<= p and b >= p):
print p
if(p > b):
break
print
I think python list remove is very slow. My code is correct but I am getting timelimit exceeded. can someone help me improve this code.
A primality testing function will perform best. There's pseudocode on the Miller-Rabin wikipedia page
Instead of removing the element that is not a prime, why not replace it with some sentinel value, perhaps -1 or None? Then when printing, just print the values that aren't sentinels.
Use a list of length (n-m), and then the index for number i is x[m+i].
remove() isn't slow in the grand scheme of things, it's just that the code calls it a LOT.
As dappawit suggests, rather than modifying the list, change the value in the list so you know that it isn't a valid number to use.
I also see that when you generate the set of prime numbers, you use range(2,maxrange) which is okay, but not efficient if the lower bound is much greater than 2. You'll be wasting computing time on generating primes that aren't even relevant to the problem space. If nothing else, keep track of minrange as well as maxrange.
A bug with your original code is that you use range(2,maxrange). That means maxrange is not in the list of numbers considered. Try 3 5 as input for a and b to see the bug.
range(2,maxrange+1) fixes the problem.
Another bug in the code is that you modify the original sequence:
From Python docs - for-statement
It is not safe to modify the sequence being iterated over in the loop (this can only happen for mutable sequence types, such as lists). If you need to modify the list you are iterating over (for example, to duplicate selected items) you must iterate over a copy. The slice notation makes this particularly convenient:
My python skills are rudimentary, but this seems to work:
Old:
primes2 = range(2,maxrange)
for i in primes:
for j in primes2:
if(j != i and j%i == 0):
primes2.remove(j)
for (a,b) in indices:
for p in primes2:
if(a<= p and b >= p):
New:
primes2 = array.array('L', range(minrange,maxrange+1))
for i in primes:
for j in primes2:
if(j != i and j%i == 0):
primes2[j-minrange] = 0
for (a,b) in indices:
for p in primes2:
if (p != 0):
if(a<= p and b >= p):
You could also skip generating the set of prime numbers and just test the numbers directly, which would work if the sets of numbers you have to generate prime numbers are not overlapping (no work duplication).
enter link description here
Here's a deterministic variant of the Miller–Rabin primality test for small odd integers in Python:
from math import log
def isprime(n):
assert 1 < n < 4759123141 and n % 2 != 0, n
# (n-1) == 2**s * d
s = 0
d = n-1
while d & 1 == 0:
s += 1
d >>= 1
assert d % 2 != 0 and (n-1) == d*2**s
for a in [2, 7, 61]:
if not 2 <= a <= min(n-1, int(2*log(n)**2)):
break
if (pow(a, d, n) != 1 and
all(pow(a, d*2**r, n) != (n-1) for r in xrange(s))):
return False
return True
The code intent is to be an executable pseudo-code.

Categories