Here are two programs for change money problem. The first one is only a recursion program that get all combinations and the second one is using dynamic programming. HOWEVER, i get into trouble when I am working on second one. It is supposed to be faster than the first one, but my program runs FOREVER to do it. I am pretty sure that I am using the dynamic programming, but i don't know what's the problem in it?
Notes: Total is the money going to be changed, units is a list with different values and stored is a dictionary to store the value of a step.
First:
def changeMoney(total, units):
if ( total == 0 ):
return [{}]
elif ( total < 0 ):
return []
else:
n = len(units)
ret = []
for i in range(0,n):
sols = changeMoney(total-units[i],units[i:n])
for sol in sols:
if ( units[i] in sol ):
sol[units[i]] += 1
else:
sol[units[i]] = 1
ret.append(sol)
return ret
print(dpChangeMoney(300,[100,50,20,10,5,2,1],{}))
Second:
import copy
def dpChangeMoney(total, units, stored):
key = ".".join(map(str,[total] + units))
if key in stored:
return stored[key]
else:
if ( total == 0 ):
return [{}]
elif ( total < 0 ):
return []
else:
n = len(units)
for i in range(0,n):
sols = copy.deepcopy(dpChangeMoney(total-
units[i],units[i:n], stored))
for sol in sols:
if ( units[i] in sol ):
sol[units[i]] += 1
else:
sol[units[i]] = 1
if key in stored:
if sol not in stored[key]:
stored[key] += [sol]
else:
stored[key] = [sol]
return stored[key]
print(dpChangeMoney(300,[100,50,20,10,5,2,1],{}))
Here's a much faster way to do this:
def dpChangeMoney(total, units, stored, min_ix=0):
if total < 0:
return []
if total == 0:
return [{}]
if min_ix == len(units):
return []
key = (total, min_ix)
if key in stored:
return stored[key]
sol_list = []
u = units[min_ix]
for c in range(total // u + 1):
sols = dpChangeMoney(total - c*u, units, stored, min_ix + 1)
for sol in sols:
if c > 0:
sol2 = sol.copy()
sol2[u] = c
else:
sol2 = sol
sol_list.append(sol2)
stored[key] = sol_list
return sol_list
If invoked as follows, it prints the number of solutions for the specified case:
print(len(dpChangeMoney(300, [100,50,20,10,5,2,1], {})))
The result is:
466800
On my system this took well under a second to run. (Of course, you could print the actual solutions, but there are a lot!)
To see the actual solutions for a total of 10:
print(dpChangeMoney(10, [100,50,20,10,5,2,1], {}))
The result is:
[{1: 10}, {1: 8, 2: 1}, {1: 6, 2: 2}, {1: 4, 2: 3}, {1: 2, 2: 4}, {2: 5}, {1: 5, 5: 1}, {1: 3, 2: 1, 5: 1}, {1: 1, 2: 2, 5: 1}, {5: 2}, {10: 1}]
i just figure out what is the problem in my algorithm. I will update a much faster algorithm after the due date. Thanks for your suggestions and instructions. E
Related
seq = 'TGCCTTGGGCACCATGCAGTACCAAACGGAACGATAGTG'
for nucleotide in seq:
if nucleotide == 'A':
a_nt = seq.count('A')
elif nucleotide == 'G':
g_nt = seq.count('G')
elif nucleotide == 'C':
c_nt = seq.count('C')
elif nucleotide == 'T':
t_nt = seq.count('T')
elif nucleotide == 'N':
n_nt = seq.count('N')
else:
sys.exit("Did not code")
print(a_nt, g_nt, c_nt, t_nt, n_nt)
Error:
NameError: name 'n_nt' is not defined. Did you mean: 'a_nt'?
If the nucleotide is not in 'AGCTN', sys.exit("no this code").
Even counts of N is zero, it should be printed out.
If I print out a, g, c, and t, it works well. But n_nt is not working.
Just count everything without the for loop, then all variables are set, even if zero:
seq = 'TGCCTTGGGCACCATGCAGTACCAAACGGAACGATAGTG'
a_nt = seq.count('A')
g_nt = seq.count('G')
c_nt = seq.count('C')
t_nt = seq.count('T')
n_nt = seq.count('N')
print(a_nt, g_nt, c_nt, t_nt, n_nt)
# or more efficient
from collections import Counter
counts = Counter(seq)
for letter in 'AGCTN':
print(counts[letter], end=' ')
Output:
11 11 10 7 0
11 11 10 7 0
I suggest using collections.Counter
from collections import Counter
possible_nucleotides = ["A", "G", "C", "N", "T"]
seq = "TGCCTTGGGCACCATGCAGTACCAAACGGAACGATAGTG"
seq_counts = Counter(seq)
missing_nucleotides = {x: 0 for x in set(possible_nucleotides) - set(seq_counts.keys())}
seq_counts.update(missing_nucleotides)
then seq_counts will look like this:
Counter({'G': 11, 'A': 11, 'C': 10, 'T': 7, 'N': 0})
Keep in mind that updating Counter is purely optional as trying to access specific key will return 0 if not present
I am trying to implement a function that will print a number of fibonacci numbers. For example if my input was fibonacci([0,1,2,3], the output would be 0,1,1,2.
I am not sure how to proceed.
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibonacci(n - 1) + fibonacci(n-2)
while True:
n.append(n)
print(fibonacci[5,10,11])
You can refactor your code a bit and get:
def fibonacci(lst):
def getTerm(n):
if n == 0:
return 0
elif n == 1:
return 1
return getTerm(n - 1) + getTerm(n-2)
return [getTerm(x) for x in lst]
Gives output:
>>> fibonacci([0,1,2,3])
[0, 1, 1, 2]
>>> fibonacci([5,10,11])
[5, 55, 89]
Avoiding redundant computations:
def fibonacci(indices):
fibs = {}
set_of_indices = set(indices)
f0 = fibs[0] = 0
f1 = fibs[1] = 1
for i in range(2,max(indices)+1):
f2 = f0+f1
if i in set_of_indices:
fibs[i] = f2
f0,f1=f1,f2
return [fibs[i] for i in indices]
My question would be how I withdraw winner based on highest score?
since u cant sort in dictionaries
i tried this with lists, but then name wouldnt appear, only the score...
a = {'name_a':0}
b = {'name_b':0}
c = {'name_c':0}
d = {'name_d':0}
e = {'name_e':0}
print("Each time someone scores a point, the letter of his name is typed in lowercase. If someone loses a point, the letter of his name is typed in uppercase")
score = input('Enter series of charachters indicating who scored a poitn: ')
for i in score:
if i == 'a':
a['name_a'] += 1
if i == 'A':
a['name_a'] -= 1
if i == 'b':
b['name_b'] += 1
if i == 'B':
b['name_b'] -= 1
if i == 'c':
c['name_c'] += 1
if i == 'C':
c['name_c'] -= 1
if i == 'd':
d['name_d'] += 1
if i == 'D':
d['name_d'] -= 1
if i == 'e':
e['name_e'] += 1
if i == 'E':
e['name_e'] -= 1
print(a,b,c,d,e)
print('Winner is: ', )
This will work:
max((i, name) for d in (a,b,c,d,e) for name, i in d.items())[1]
you probably want to use a single dict, instead of one for each, like such:
scores = {
'a': 0,
'b': 0,
'c': 0,
'd': 0,
'e': 0,
}
And then you can keep track of the highest scoring player as points are calculated:
point_scored = input('Enter series of charachters indicating who scored a point: ')
for i in point_scored:
if not scores.get(i) is None:
scores[i] += 1
elif not scores.get(i.lower()) is None:
scores[i.lower()] -= 1
else:
print(str(i) + ' is not a valid player...')
winner = max(scores, key=scores.get)
print(scores)
print('Winner is ' + winner)
max_key = ""
max_val = 0
for key, value in d.items():
if (value > max_val):
max_val = value
max_key = key
Is this what you mean?
i found the answer
winner = (sorted(d.items(), key = lambda x: int(x[1]), reverse = True))
I want to cumulatively add element on Arraystack in Python
class StockManager:
__PROFIT = 0
def __init__(self, o_name, o_surname):
self.box = ArrayStack()
self._name = o_name
self._surname = o_surname
def buy_shares(self, company, number, buy_price):
StockManager.__PROFIT -= buy_price * number
n = 0
if len(self.box) < 2:
"""there is no overlapped elements when box has no element"""
self.box.push(company)
self.box.push(number)
else:
while n < len(self.box):
if self.box._data[n] == company:
"""every even index(n = 0, 2, 4, ...) refers to company name"""
"""every odd index(n = 1, 3, 5, ...), which is next to even index refers to number of buying"""
self.box._data[n + 1] += number
n += 2
elif self.box._data[n] != company:
""" if there's no overlapping, then just put the elements """
self.box.push(company)
self.box.push(number)
n += 2
return print(self.box._data)
and class Arraystack is like this:
class ArrayStack:
"""LIFO Stack implementation using a Python list as underlying storage."""
def __init__(self):
"""Create an empty stack."""
self._data = [] # nonpublic list instance
def __len__(self):
"""Return the number of elements in the stack."""
return len(self._data)
def is_empty(self):
"""Return True if the stack is empty."""
return len(self._data) == 0
def push(self, e):
"""Add element e to the top of the stack."""
self._data.append(e) # new item stored at end of list
def top(self):
"""Return (but do not remove) the element at the top of the stack.
Raise Empty exception if the stack is empty.
"""
if self.is_empty():
raise AssertionError('Stack is empty')
return self._data[-1] # the last item in the list
def pop(self):
"""Remove and return the element from the top of the stack (i.e., LIFO).
Raise Empty exception if the stack is empty.
"""
if self.is_empty():
raise AssertionError('Stack is empty')
return self._data.pop() # remove last item from list
def print_contents(self):
print("Stack content: {0}".format(self._data))
when I run stockmanager with
if __name__ == '__main__':
P = StockManager("A","B")
P.buy_shares("hyundai", 20, 100)
P.buy_shares("hyundai", 20, 100)
P.buy_shares("hyundai", 20, 100)
P.buy_shares("lg", 20, 100)
the result is
['hyundai', 20] => O.K
['hyundai', 40] => O.K
['hyundai', 60] => O.K
['hyundai', 60, 'lg', 40] => It should be ['hyundai', 60, 'lg', 20]
['hyundai', 60, 'lg', 60, 'lg', 40] => don't know why this result comes...
How can I handle this problem?
So, the problem lies in your while loop:
while n < len(self.box):
if self.box._data[n] == company:
"""every even index(n = 0, 2, 4, ...) refers to company name"""
"""every odd index(n = 1, 3, 5, ...), which is next to even index refers to number of buying"""
self.box._data[n + 1] += number
n += 2
elif self.box._data[n] != company:
""" if there's no overlapping, then just put the elements """
self.box.push(company)
self.box.push(number)
n += 2
Imagine we've run:
P = StockManager("A","B")
P.buy_shares("hyundai", 20, 100)
P.buy_shares("hyundai", 20, 100)
P.buy_shares("hyundai", 20, 100)
And so far, everything has worked as planned. Now, you try:
P.buy_shares("lg", 20, 100)
So: n == 0 and len(self.box) == 2, so we enter the loop.
The if condition fails, self.box._data[n] != 'lg', so we go to the elif block:
self.box.push(company)
self.box.push(number)
n += 2
Now, box == ['hyundai', 60, 'lg', 20] and n == 2. But wait! The loop condition is n < len(box), but len(box) == 4, so we enter the while-loop again! This time, the if conditions passes this time since self.box._data[2] == 'lg'.
So you execute the body of the if-block:
self.box._data[n + 1] += number
n += 2
Now, n == 4 and box == ['hyundai', 60, 'lg', 40]. This time, 4 < len(box) fails and we exit the loop and your function ends.
Now, a stack seems like the wrong data structure to me. It's clunky to have to increase the size by two. If you really wanted to do this, I would suggest an approach like
offset = 0
i = -2
for i in range(0, len(self.box), 2):
if self.box._data[n] == company:
break
else:
offset = 2
self.box.push(company)
self.box.push(0)
self.box._data[i + offset + 1] += number
But again, this is clunky. You would be better off using a dict for box, then the logic could be implemented simply as:
self.box[company] = self.box.get(company, 0) + 1
Or better yet, use a defaultdict
>>> from collections import defaultdict
>>> box = defaultdict(int)
>>> box
defaultdict(<class 'int'>, {})
>>> box['lg'] += 20
>>> box
defaultdict(<class 'int'>, {'lg': 20})
>>> box['lg'] += 20
>>> box
defaultdict(<class 'int'>, {'lg': 40})
>>> box['lg']
40
You are iterating over an entire list using indices; if the first company/number doesn't match the stock you are buying, it is automatically appended to the end of the list; then the next set of indices will point to the new company that was just appended so it adds the number. The elif is incorrect - you shouldn't append a new company/number pair till you have iterated through the whole list and didn't find it.
This is what you are doing
>>> a = ['a',1]
>>> n = 0
>>> comp, nbr = 'b', 2
>>> while n < len(a):
.... if a[n] == comp:
print('comp found at', n)
a[n+1] += nbr
n += 2
else:
print('n =', n, 'appending', comp)
a.append(comp)
a.append(nbr)
n += 2
n = 0 appending b
comp found at 2
>>>
This is what you could do to fix it:
>>> a = ['a',1]
>>> n = 0
>>> comp, nbr = 'b', 2
>>> while n < len(a):
found = False
if a[n] == comp:
print('comp found at', n)
a[n+1] += nbr
found = True
n += 2
>>> if not found:
a.append(comp)
a.append(nbr)
>>> a
['a', 1, 'b', 2]
>>>
But as suggested in the comments, you would probably be better off storing your purchase in a dictionary.
I have the following attempt at a recursive function to create a shift table within a dictionary:
def createShiftTable(alphabet,T,shiftT):
if not T:
for char in alphabet:
shiftT[char] = len(T)+1
return shiftT
else:
return createShiftTable(alphabet,T[1:],shiftT)
shiftT[T[0]] = len(T)
al=['a','b','c','d']
T = "aaabbdddaaba"
print(createShiftTable(al,T,{}))
This is returning {'a': 1, 'c': 1, 'b': 1, 'd': 1}
I'd like it to return {'a': 1, 'c': 13, 'b': 2, 'd': 5}
Non-recursively the following works ok but how do I get the above recursive function working?
def createShiftTableX(alphabet,T):
shiftT={}
for char in al:
shiftT[char] = len(T)+1
for i in range(len(T)):
shiftT[T[i]] = len(T)-i
return shiftT
al=['a','b','c','d']
T = "aaabbdddaaba"
print(createShiftTableX(al,T))
How about this:
def createShiftTableX(alphabet, T):
l = len(T)
for c in alphabet:
i = T.find(c)
if i<0:
yield l
else:
yield i+1
al=['a','b','c','d']
T = "aaabbdddaaba"
print(list(createShiftTableX(al,T)))
You should run this in a debugger or put in some logging or print statements to see what it is actually doing.