Dynamic programming for primitive calculator - python

I'm dealing with the problem, that is pretty similar to change coins problem.
I need to implement a simple calculator, that can perform the following three operations with the current number x: multiply x by 2, multiply x by 3, or add 1 to x.
Goal is given a positive integer n, find the minimum number of operations needed to obtain the number n starting from the number 1.
I made a greedy approach to that, bur it shows incorrect results
import sys
def optimal_sequence(n):
sequence = []
while n >= 1:
sequence.append(n)
if n % 3 == 0:
n = n // 3
elif n % 2 == 0:
n = n // 2
else:
n = n - 1
return reversed(sequence)
input = sys.stdin.read()
n = int(input)
sequence = list(optimal_sequence(n))
print(len(sequence) - 1)
for x in sequence:
print(x)
For example:
Input: 10
Output:
4
1 2 4 5 10
4 steps. But the correct one is 3 steps:
Output:
3
1 3 9 10
I read about dynamic programming, and hope I could implement it here. But, I can't get how to use it properly in particular case, can someone give me an advice?

Just solve it with a simple recursion and Memoization:
Code:
d = {}
def f(n):
if n == 1:
return 1, -1
if d.get(n) is not None:
return d[n]
ans = (f(n - 1)[0] + 1, n - 1)
if n % 2 == 0:
ret = f(n // 2)
if ans[0] > ret[0]:
ans = (ret[0] + 1, n // 2)
if n % 3 == 0:
ret = f(n // 3)
if ans[0] > ret[0]:
ans = (ret[0] + 1, n // 3)
d[n] = ans
return ans
def print_solution(n):
if f(n)[1] != -1:
print_solution(f(n)[1])
print n,
def solve(n):
print f(n)[0]
print_solution(n)
print ''
solve(10)
Hint: f(x) returns a tuple (a, b), which a denotes the minimum steps to get x from 1, and b denotes the previous number to get the optimum solution. b is only used for print the solution.
Output:
4 # solution for 10
1 3 9 10
7 # solution for 111
1 2 4 12 36 37 111
You may debug my code and to learn how it works. If you are beginner at DP, you could read my another SO post about DP to get a quick start.
Since Python can't recurse a lot (about 10000), I write an iterative version:
# only modified function print_solution(n) and solve(n)
def print_solution(n):
ans = []
while f(n)[1] != -1:
ans.append(n)
n = f(n)[1]
ans.append(1)
ans.reverse()
for x in ans:
print x,
def solve(n):
for i in range(1, n):
f(i)[0]
print_solution(n)
print ''
solve(96234) # 1 3 9 10 11 22 66 198 594 1782 5346 16038 16039 32078 96234

Related

Use Recursion to Find Distinct Ways N can be computed

Was recently trying to solve this coding challenge from a company and I was stumped.
Let T(n) denote the number of different ways that a value of n cents, where n >= 4 and n is even, can be made by using 4-cent and 6-cent coins. For example, if n = 12 then we can use 3 4-cent coins or 2 6-cent coins, so T(12) = 2. Write a recursive algorithm in Python to find T(n) for n >= 4 and n is even.
I nailed down the base cases to be T(n < 4 or n not even) = 0, T(4) = 1 distinct way (1 4-cent coin) and T(6) = 1 distinct way (1 6-cent coin). But I'm not entirely sure how to proceed with a value greater than 6 and is even. Actually, if n > 4 and is even I did think of using modulo (%), so
if(n % 4 == 0): increment count
if(n % 6 == 0): increment count
I guess, I'm stuck on the recursive part because the two if-statements I've computed would count as only a single a way whereas there can be multiple ways to compute N.
Not recursive, but should help you get started.
To determine unique solutions, you are basically asking for partitions of N such that N1 + N2 = N and N1 % 4 == 0 and N2 % 6 == 0. An iterative solution would go something like this:
count = 0
for j in range(0, N + 1, 4):
if (N - j) % 6 == 0:
count += 1
Turning this loop into a recursion is trivial:
def count(N):
def count4(N, n4):
if n4 > N:
return 0
return int((N - n4) % 6 == 0) + count4(N, n4 + 4)
if N < 4 or N % 2:
return 0
return count4(N, 0)
Assuming that ways means "exact order in which coins are laid out", here is a recursive solution.
def T_recurse (n):
if 0 == n:
return 1
elif n < 3:
return 0
else:
return T_recurse(n - 4) + T_recurse(n - 6)
print(T_recurse(100))
And a faster solution
def T_iter(n):
if n < 0:
return 0
else:
answers = [1, 0, 0, 0, 1, 0]
while len(answers) <= n:
answers.append(answers[-4] + answers[-6])
return answers[n]
print(T_iter(100))
(There is also an analytical solution involving the roots of the polynomial x^6 - x^2 - 1, but that is slower to calculate in practice.)
Assuming that ways means "this many of one, that many of the other", then here is a recursive solution:
def S_recurse (n, coins):
if 0 == n:
return 1
elif n < 0:
return 0
elif len(coins) == 0:
return 0
else:
return S_recurse(n - coins[0], coins) + S_recurse(n, coins[1:])
S_recurse(12, [4, 6])
The recursive slowdown is not as bad though still exponential. However but iterative gives you quadratic:
def S_iter (n, coins):
last_row = [0 for i in range(n + 1)]
last_row[0] = 1
for coin in coins:
this_row = []
for i in range(n+1):
if i < coin:
this_row.append(last_row[i])
else:
this_row.append(last_row[i] + this_row[i - coin])
last_row = this_row
return last_row[n]
You can use an optional parameter to keep track of the current sum of 6-cent coins for a given recursive call, and return 1 when the given number is divisible by 4 after deducting the sum of 6's:
def count46(n, sum6=0):
return sum6 <= n and (((n - sum6) % 4) == 0) + count46(n, sum6 + 6)
so that:
for i in range(4, 24, 2):
print(i, count_4_6(i))
outputs:
4 1
6 1
8 1
10 1
12 2
14 1
16 2
18 2
20 2
22 2
Not the most optimized but it returns an array of all distinct solutions
def coins(n, sum=0, current=[], answers=[]):
if sum > n:
return
if sum == n:
answers.append(current)
return
a4 = list(current)
a4.append(4)
coins(n, sum+4, a4, answers)
lastIndex = len(current) - 1
if len(current) == 0 or current[lastIndex] == 6:
a6 = list(current)
a6.append(6)
coins(n, sum+6, a6, answers)
return answers
Try it online!

Codewars. Some tests are passed, but i need to get tests which outputs the following mistake: 3263 should equal -1

Can you explain it what problems are here? To my mind, this code is like a heap of crap but with the right solving. I beg your pardon for my english.
the task of this kata:
Some numbers have funny properties. For example:
89 --> 8¹ + 9² = 89 * 1
695 --> 6² + 9³ + 5⁴= 1390 = 695 * 2
46288 --> 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51
Given a positive integer n written as abcd... (a, b, c, d... being digits) and a positive integer p we want to find a positive integer k, if it exists, such as the sum of the digits of n taken to the successive powers of p is equal to k * n. In other words:
Is there an integer k such as : (a ^ p + b ^ (p+1) + c ^(p+2) + d ^ (p+3) + ...) = n * k
If it is the case we will return k, if not return -1.
Note: n, p will always be given as strictly positive integers.
dig_pow(89, 1) should return 1 since 8¹ + 9² = 89 = 89 * 1
dig_pow(92, 1) should return -1 since there is no k such as 9¹ + 2² equals 92 * k
dig_pow(695, 2) should return 2 since 6² + 9³ + 5⁴= 1390 = 695 * 2
dig_pow(46288, 3) should return 51 since 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51
def dig_pow(n, p):
if n > 0 and p > 0:
b = []
a = str(n)
result = []
for i in a:
b.append(int(i))
for x in b:
if p != 1:
result.append(x ** p)
p += 1
else:
result.append(x ** (p + 1))
if int((sum(result)) / n) < 1:
return -1
elif int((sum(result)) / n) < 2:
return 1
else:
return int((sum(result)) / n)
test results:
Test Passed
Test Passed
Test Passed
Test Passed
3263 should equal -1
I don't know what exact version of Python you're using. This following code are in Python 3. And if I get you correctly, the code can be as simple as
def dig_pow(n, p):
assert n > 0 and p > 0
digits = (int(i) for i in str(n)) # replaces your a,b part with generator
result = 0 # you don't use result as a list, so an int suffice
for x in digits: # why do you need if in the loop? (am I missing something?)
result += x ** p
p += 1
if result % n: # you just test for divisibility
return -1
else:
return result // n
The major problem is that, in your objective, you have only two option of returning, but you wrote if elif else, which is definitely unnecessary and leads to problems and bugs. The % is modulus operator.
Also, having an if and not returning anything in the other branch is often not a good idea (see the assert part). Of course, if you don't like it, just fall back to if.
I believe this could work as well and I find it a little easier to read, however it can definitely be improved:
def dig_pow(n, p):
value = 0
for digit in str(n):
value += int(digit)**p
p += 1
for k in range(1,value):
if value/k == n:
return k
return -1
this is some example simple example than using:
digits = (int(i) for i in str(n))
I'm opting to use this version since I am still a beginner which can be done with this alt way:
result = 0
for digits in str(n):
#iterate through each digit from n
# single of digits turn to int & power to p
for number in digits:
result += int(number) ** p
p += 1
as for the full solution, it goes like this:
def dig_pow(n, p):
# example n = 123 , change it to string = 1, 2, 3
# each string[] **p, and p iterate by 1
# if n % p not equal to p return - 1
result = 0
for digits in str(n):
#iterate through each digit from n
# single digit turn to int & power to p
for number in digits:
result += int(number) ** p
p += 1
if result % n:
return -1
else:
return result // n

Probability of finding a prime (using miller-rabin test)

I've implemented Miller-Rabin primality test and every function seems to be working properly in isolation. However, when I try to find a prime by generating random numbers of 70 bits my program generates in average more than 100000 numbers before finding a number that passes the Miller-Rabin test (10 steps). This is very strange, the probability of being prime for a random odd number of less than 70 bits should be very high (more than 1/50 according to Hadamard-de la Vallée Poussin Theorem). What could be wrong with my code? Would it be possible that the random number generator throws prime numbers with very low probability? I guess not... Any help is very welcome.
import random
def miller_rabin_rounds(n, t):
'''Runs miller-rabin primallity test t times for n'''
# First find the values r and s such that 2^s * r = n - 1
r = (n - 1) / 2
s = 1
while r % 2 == 0:
s += 1
r /= 2
# Run the test t times
for i in range(t):
a = random.randint(2, n - 1)
y = power_remainder(a, r, n)
if y != 1 and y != n - 1:
# check there is no j for which (a^r)^(2^j) = -1 (mod n)
j = 0
while j < s - 1 and y != n - 1:
y = (y * y) % n
if y == 1:
return False
j += 1
if y != n - 1:
return False
return True
def power_remainder(a, k, n):
'''Computes (a^k) mod n efficiently by decomposing k into binary'''
r = 1
while k > 0:
if k % 2 != 0:
r = (r * a) % n
a = (a * a) % n
k //= 2
return r
def random_odd(n):
'''Generates a random odd number of max n bits'''
a = random.getrandbits(n)
if a % 2 == 0:
a -= 1
return a
if __name__ == '__main__':
t = 10 # Number of Miller-Rabin tests per number
bits = 70 # Number of bits of the random number
a = random_odd(bits)
count = 0
while not miller_rabin_rounds(a, t):
count += 1
if count % 10000 == 0:
print(count)
a = random_odd(bits)
print(a)
The reason this works in python 2 and not python 3 is that the two handle integer division differently. In python 2, 3/2 = 1, whereas in python 3, 3/2=1.5.
It looks like you should be forcing integer division in python 3 (rather than float division). If you change the code to force integer division (//) as such:
# First find the values r and s such that 2^s * r = n - 1
r = (n - 1) // 2
s = 1
while r % 2 == 0:
s += 1
r //= 2
You should see the correct behaviour regardless of what python version you use.

Python function returning first value twice

I've written this function to calculate sin(x) using Taylor series to any specified degree of accuracy, 'N terms', my problem is the results aren't being returned as expected and I can't figure out why, any help would be appreciated.
What is am expecting is:
1 6.28318530718
2 -35.0585169332
3 46.5467323429
4 -30.1591274102
5 11.8995665347
6 -3.19507604213
7 0.624876542716
8 -0.0932457590621
9 0.0109834031461
What I am getting is:
1 None
2 6.28318530718
3 -35.0585169332
4 46.5467323429
5 -30.1591274102
6 11.8995665347
7 -3.19507604213
8 0.624876542716
9 -0.0932457590621
Thanks in advance.
def factorial(x):
if x <= 1:
return 1
else:
return x * factorial(x-1)
def sinNterms(x, N):
x = float(x)
while N >1:
result = x
for i in range(2, N):
power = ((2 * i)-1)
sign = 1
if i % 2 == 0:
sign = -1
else:
sign = 1
result = result + (((x ** power)*sign) / factorial(power))
return result
pi = 3.141592653589793
for i in range(1,10):
print i, sinNterms(2*pi, i)
I see that you are putting the return under the for which will break it out of the while loop. You should explain if this is what you mean to do. However, given the for i in range(1,10): means that you will ignore the first entry and return None when the input argument i is 1. Is this really what you wanted? Also, since you always exit after the calculation, you should not do a while N > 1 but use if N > 1 to avoid infinite recursion.
The reason why your results are off is because you are using range incorrectly. range(2, N) gives you a list of numbers from 2 to N-1. Thus range(2, 2) gives you an empty list.
You should calculate the range(2, N+1)
def sinNterms(x, N):
x = float(x)
while N >1:
result = x
for i in range(2, N):
Your comment explains that you have the lines of code in the wrong order. You should have
def sinNterms(x, N):
x = float(x)
result = x
# replace the while with an if since you do not need a loop
# Otherwise you would get an infinite recursion
if N > 1:
for i in range(2, N+1):
power = ((2 * i)-1)
sign = 1
if i % 2 == 0:
sign = -1
# The else is not needed as this is the default
# else:
# sign = 1
# use += operator for the calculation
result += (((x ** power)*sign) / factorial(power))
# Now return the value with the indentation under the if N > 1
return result
Note that in order to handle things set factorial to return a float not an int.
An alternative method that saves some calculations is
def sinNterms(x, N):
x = float(x)
lim = 1e-12
result = 0
sign = 1
# This range gives the odd numbers, saves calculation.
for i in range(1, 2*(N+1), 2):
# use += operator for the calculation
temp = ((x ** i)*sign) / factorial(i)
if fabs(temp) < lim:
break
result += temp
sign *= -1
return result

How can I improve my code for euler 14?

I solved Euler problem 14 but the program I used is very slow. I had a look at what the others did and they all came up with elegant solutions. I tried to understand their code without much success.
Here is my code (the function to determine the length of the Collatz chain
def collatz(n):
a=1
while n!=1:
if n%2==0:
n=n/2
else:
n=3*n+1
a+=1
return a
Then I used brute force. It is slow and I know it is weak. Could someone tell me why my code is weak and how I can improve my code in plain English.
Bear in mind that I am a beginner, my programming skills are basic.
Rather than computing every possible chain from the start to the end, you can keep a cache of chain starts and their resulting length. For example, for the chain
13 40 20 10 5 16 8 4 2 1
you could remember the following:
The Collatz chain that starts with 13 has length 10
The Collatz chain that starts with 40 has length 9
The Collatz chain starting with 20 has length 8
... and so on.
We can then use this saved information to stop computing a chain as soon as we encounter a number which is already in our cache.
Implementation
Use dictionaries in Python to associate starting numbers with their chain length:
chain_sizes = {}
chain_sizes[13] = 10
chain_sizes[40] = 9
chain_sizes[40] # => 9
20 in chain_sizes # => False
Now you just have to adapt your algorithm to make use of this dictionary (filling it with values as well as looking up intermediate numbers).
By the way, this can be expressed very nicely using recursion. The chain sizes that can occur here will not overflow the stack :)
Briefly, because my English is horrible ;-)
Forall n >= 1, C(n) = n/2 if n even,
3*n + 1 if n odd
It is possible to calculate several consecutive iterates at once.
kth iterate of a number ending in k 0 bits:
C^k(a*2^k) = a
(2k)th iterate of a number ending in k 1 bits:
C^(2k)(a*2^k + 2^k - 1) = a*3^k + 3^k - 1 = (a + 1)*3^k - 1
Cf. formula on Wikipédia article (in French); see also my website (in French), and Module tnp1 in my Python package DSPython.
Combine the following code with the technique of memoization explained by Niklas B :
#!/usr/bin/env python
# -*- coding: latin-1 -*-
from __future__ import division # Python 3 style in Python 2
from __future__ import print_function # Python 3 style in Python 2
def C(n):
"""Pre: n: int >= 1
Result: int >= 1"""
return (n//2 if n%2 == 0
else n*3 + 1)
def Ck(n, k):
"""Pre: n: int >= 1
k: int >= 0
Result: int >= 1"""
while k > 0:
while (n%2 == 0) and k: # n even
n //= 2
k -= 1
if (n == 1) and k:
n = 4
k -= 1
else:
nb = 0
while (n > 1) and n%2 and (k > 1): # n odd != 1
n //= 2
nb += 1
k -= 2
if n%2 and (k == 1):
n = (n + 1)*(3**(nb + 1)) - 2
k -= 1
elif nb:
n = (n + 1)*(3**nb) - 1
return n
def C_length(n):
"""Pre: n: int >= 1
Result: int >= 1"""
l = 1
while n > 1:
while (n > 1) and (n%2 == 0): # n even
n //= 2
l += 1
nb = 0
while (n > 1) and n%2: # n odd != 1
n //= 2
nb += 1
l += 2
if nb:
n = (n + 1)*(3**nb) - 1
return l
if __name__ == '__main__':
for n in range(1, 51):
print(n, ': length =', C_length(n))

Categories