Working out the binomial coefficient in python using memoization - python-3.x

I'm trying to teach myself dynamic programming and was practicing a question from http://www.geeksforgeeks.org/dynamic-programming-set-9-binomial-coefficient/. I first attempted the question in Java and my code gives the correct results. Java code:
static int calculate(int n, int k){
if(k == 0 || k == n)
return 1;
if(dp[n][k] != Integer.MAX_VALUE)
return dp[n][k];
else
dp[n][k] = calculate(n - 1, k -1) + calculate(n-1, k );
return dp[n][k];
}
However, when I tried to implement the same thing in Python, I could not and am getting strange results, e.g. when n is 5 and k is 2 I get 13, not 10. I'm quite new to Python so may be missing something obvious but if anyone could help that would be greatly appreciated. Python code:
dp = [[-1] * 3] * 6
def calculate(n, k):
if n == k or k == 0:
return 1
if dp[n][k] > 0:
return dp[n][k]
else:
dp[n][k] = calculate(n-1, k-1) + calculate(n-1, k)
return dp[n][k]

I think there is no need of this condition if dp[n][k] > 0:.
Try it :
dp = [[-1] * 3] * 6
def calculate(n, k):
if n == k or k == 0:
return 1
dp[n][k] = calculate(n-1, k-1) + calculate(n-1, k)
return dp[n][k]
Link : Working code

Everything in your code is correct except the initialization. This might have happened because you might not be completely aware how lists work.
Look at this statement and lets understand what it does:
dp = [[-1] * 3] * 6
Operator * just replicates copies of whatever provided as list. So all the lists are essentially same and referencing to one list.
To avoid this you must initialize it individually. Something like this:
dp = [[-1 for j in range(100)] for i in range(100)]
So the modified code would become something like this.(Just has change in initialization method.)
dp = [[-1 for j in range(100)] for i in range(100)]
def calculate(n, k):
if n == k or k == 0:
return 1
if dp[n][k] > 0:
return dp[n][k]
else:
dp[n][k] = calculate(n-1, k-1) + calculate(n-1, k)
return dp[n][k]
print(calculate(5,2))
As an advice, normally lists are not used for implementing memoization in python instead other methods are used which you might want to look on your own.

Related

The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17. Find the sum of all the primes below two million

sum_ans=17
for i in range(11,2000000):
for j in range(2,int(i**0.5)):
if i%j==0:
break
else:
sum_ans+=i
print(sum_ans)
The code i have return gives answer 143064094781 and the correct answer is 142913828922 but i can not figure out where i have gone wrong. So can any one help me.
Range's stop parameter is exclusive. This means that your code is only calculating j from 2 to 1 less than i**0.5. To fix this you can add 1, meaning that your end code will look a little like this, providing the correct output of 142913828922:
sum_ans=17
for i in range(11,2000000):
for j in range(2,int(i**0.5+1)):
if i%j==0:
break
else:
sum_ans+=i
print(sum_ans)
What about about this:
def isPrime(x):
prime = True
for i in range(2, x):
if x % i == 0:
prime = False
break
else:
continue
return prime
primes = (a for a in range(2, 2000000) if isPrime(a))
print(sum(primes))
# output
142913828922
This code will take a few minutes to execute. Buckle up!!
def sumPrimes(n):
sum =0
for i in range(2 ,n):
for j in range(2, int(i / 2) +1):
if (i % j) == 0:
break
else:
sum += i
return sum
print(sumPrimes(2000000))
If you iterating over all numbers below 2 million, you might as well sieve them using the Sieve of Eratoshenes:
from math import ceil, sqrt
def sieve(n):
nums = list(range(2,n+1))
primes = []
p = 2
k = 1+ ceil(sqrt(n))
while p < k:
primes.append(p)
nums = [num for num in nums[1:] if num % p > 0]
p = nums[0]
return primes + nums
Then sum(sieve(2000000)) evaluates to 142913828922. It takes about 5 seconds to run on my machine.

I want to return the sum of all indexes in n via recursion. How do I do this?

def final_sum(n):
n = str(n)
if int(n) == 0:
return 0
else:
x = int(n[0])
return x + int(final_sum(n[1:]))
print(final_sum(123))
For example, if my n is 123, I should be getting 6. But I am having an error in this code. Can anyone help? I have to use recursive function. So tell me what's wrong with the code.
in return x + int(final_sum(n[1:])), n[1:] is str type
in the beginning of the function, with n = str(n), you assume the input is an int
Besides, you did not consider the case that n[1:] can be empty in return x + int(final_sum(n[1:])).
Here is an anwser based on your code
def final_sum(n):
if n == 0:
return 0
n = str(n)
x = int(n[0])
if len(n)==1:
return x
else:
return x + final_sum(int(n[1:]))
Here is another version using % operation
def final_sum(n):
if n < 10:
return n
return n % 10 + final_sum(n // 10)
First of all, at the beggining I would do this instead of casting back and forth:
def final_sum(n):
if n<10:
return n
You see, the problem is, in the last recursive iteration, you are passing this to the function:
final_sum("")
When you should be passing an int. I think this is happening because your last cast is backwards and you never check how many digits the number has. So the code should look like this:
def final_sum(n):
if n<10:
return n
n = str(n)
x = int(n[0])
return x + final_sum(int(n[1:]))
print(final_sum(123))

Is it possible to merge these two functions as one calls on another

Would like to know if it is possible to merge these two functions together it seems like it could be a singular function through recursion but i'm not sure. I don't really do a lot of programming but this works as intended i just thought it would be nice to have it as a single function. Just not sure how to program recursion any advice would be great thanks
def sieve(A, n):
for i in A:
if i % n == 0 and i > n:
A.remove(i)
return A
def primelist(N):
A = [i for i in range(2, N + 1)]
for i in A:
A = (sieve(A, i))
print(A)
Decided on a new approach and solved:
def primelist(N):
k = 0
A = [i for i in range(2, N + 1)]
while k < len(A):
for i in A:
if i % A[k] == 0 and i > A[k]:
A.remove(i)
k += 1
return(A)
Decided on a new approach and solved:
We can do better -- your solution, and that of #ikuamike, have the same issue. These lines in particular are inefficient:
for i in A:
if i % A[k] == 0 and i > A[k]:
First, when possible, we should do an easier test before a harder test, so the if should really be:
for i in A:
if i > A[k] and i % A[k] == 0:
to do the comparison (subtraction) test ahead of the modulus (division) test. (Why do all those divisions when you don't need too?)
The next issue is that all the numbers from A[0] to A[k] don't need to be tested as they're eliminated by the comparison, so why not leave them out in the first place:
for i in A[k + 1:]:
if i % A[k] == 0:
Revised code:
def primelist(N):
k = 0
A = [i for i in range(2, N + 1)]
while k < len(A):
for i in A[k + 1:]:
if i % A[k] == 0:
A.remove(i)
k += 1
return A
With N set to 10,000, you can measure the time improvement.
def primelist(N):
A = [i for i in range(2, N + 1)]
new_a = A
for i in A:
for n in new_a:
if n % i == 0 and n > i:
new_a.remove(n)
print(new_a)
This should work well for you, I just replaced the for loop in seive onto the primelist function.

Using Recursive Functions in Python to find Factors of a Given Number

Have tried searching for this, but can't find exactly what I'm looking for.
I want to make a function that will recursively find the factors of a number; for example, the factors of 12 are 1, 2, 3, 4, 6 & 12.
I can write this fairly simply using a for loop with an if statement:
#a function to find the factors of a given number
def print_factors(x):
print ("The factors of %s are:" % number)
for i in range(1, x + 1):
if number % i == 0: #if the number divided by i is zero, then i is a factor of that number
print (i)
number = int(input("Enter a number: "))
print (print_factors(number))
However, when I try to change it to a recursive function, I am getting just a loop of the "The factors of x are:" statement. This is what I currently have:
#uses recursive function to print all the letters of an integer
def print_factors(x): #function to print factors of the number with the argument n
print ("The factors of %s are:" % number)
while print_factors(x) != 0: #to break the recursion loop
for i in range(1,x + 1):
if x % i == 0:
print (i)
number = int(input("Enter a number: "))
print_factors(number)
The error must be coming in either when I am calling the function again, or to do with the while loop (as far as I understand, you need a while loop in a recursive function, in order to break it?)
There are quite many problems with your recursive approach. In fact its not recursive at all.
1) Your function doesn't return anything but your while loop has a comparision while print_factors(x) != 0:
2) Even if your function was returning a value, it would never get to the point of evaluating it and comparing due to the way you have coded.
You are constantly calling your function with the same parameter over and over which is why you are getting a loop of print statements.
In a recursive approach, you define a problem in terms of a simpler version of itself.
And you need a base case to break out of recursive function, not a while loop.
Here is a very naive recursive approach.
def factors(x,i):
if i==0:
return
if x%i == 0:
print(i)
return factors (x,i-1) #simpler version of the problem
factors(12,12)
I think we do using below method:
def findfactor(n):
factorizeDict
def factorize(acc, x):
if(n%x == 0 and n/x >= x):
if(n/x > x):
acc += [x, n//x]
return factorize(acc, x+1)
else:
acc += [x]
return acc
elif(n%x != 0):
return factorize(acc, x+1)
else:
return acc
return factorize(list(), 1)
def factors(x,i=None) :
if i is None :
print('the factors of %s are : ' %x)
print(x,end=' ')
i = int(x/2)
if i == 0 :
return
if x % i == 0 :
print(i,end=' ')
return factors(x,i-1)
num1 = int(input('enter number : '))
print(factors(num1))
Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding things like mutations, variable reassignments, and other side effects. That said, here's how I'd write factors -
def factors(n, m = 2):
if m >= n:
return
if n % m == 0:
yield m
yield from factors(n, m + 1)
print(list(factors(10))) # [2,5]
print(list(factors(24))) # [2,3,4,6,8,12]
print(list(factors(99))) # [3,9,11,33]
And here's prime_factors -
def prime_factors(n, m = 2):
if m > n:
return
elif n % m == 0:
yield m
yield from prime_factors(n // m, m)
else:
yield from prime_factors(n, m + 1)
print(list(prime_factors(10))) # [2,5]
print(list(prime_factors(24))) # [2,2,2,3]
print(list(prime_factors(99))) # [3,3,11]
def fact (n , a = 2):
if n <= a :
return n
elif n % a != 0 :
return fact(n , a + 1 )
elif n % a == 0:
return str(a) + f" * {str(fact(n / a , a ))}"
Here is another way. The 'x' is the number you want to find the factors of. The 'c = 1' is used as a counter, using it we'll divide your number by 1, then by 2, all the way up to and including your nubmer, and if the modular returns a 0, then we know that number is a factor, so we print it out.
def factors (x,c=1):
if c == x: return x
else:
if x%c == 0: print(c)
return factors(x,c+1)

Trouble with variables (Python)

I'm a newbie with programming and I'm in trouble with this code:
def supercalcx(a, b):
n = a
while a <= b:
n = n * a
a = a + 1
print(n)
The IDE give me the error: "TypeError: can't multiply sequence by non-int of type 'str'", but I'm sure the inputs are ints or floats, can anyone explain me the problem. Thanks !
This function works:
>>> def supercalcx(a, b):
... n = a
... while a <= b:
... n = n * a
... a = a + 1
... print(n)
...
>>> supercalcx(2, 4)
48
Your function does not convert between data types. A very crude method of this is to do the following below:
def supercalcx(a,b):
n = int(a)
a = int(a)
b = int(b)
while a <= b:
n = n * a
a = a + 1
print(n)
A couple of suggestions to improve your code:
A function should rarely have the print() function inside of it; instead, use the return keyword. You can change a = a + 1 to a += 1 and n = n * a to n *= a. You can also introduce try and except which will attempt to perform whatever is tabbed under try and if something throws an error specified by the except block, it will then perform whatever is tabbed under except. A somewhat improved version is below:
def supercalcx(a, b):
try:
n = int(a)
a = int(a)
b = int(b)
except ValueError:
return "Unable to convert to integers!"
while a <= b:
n *= a
a += 1
return n
print(supercalcx("1", 2))
print(supercalcx(1, 2))

Resources