Using tree recursion to solve coin change question - python

Given a positive integer change, a set of coins makes change for change if the sum of the values of the coins is change. We will use standard US Coin values: 1, 5, 10, 25.
I was asked to solve this coin change question with recursion function only(while and for loop are not allowed), and I am very struggling with it. Please help!
def next_smaller_coin(coin):
"""Returns the next smaller coin in order."""
if coin = 25:
return 10
elif coin = 10:
return 5
elif coin = 5:
return 1
def count_coins(change):
if change == 0:
return 1
elif change < 0:
return 0
else:
with_coin = count_coins(change - next_smaller_coin(coins))
wo_coin = count_coins(change)
return with_coin + wo_coin

Related

Python loop not adding to list, therefore not providing an output

I am making a piece of code that generates bingo cards. It makes sure that there are going to be 5 numbers on each horizontal row and that each vertical column has the numbers between 1-9, 10-19, 20-29, 30-39, 40-49, 50-59, 60-69, 70-79, and 80-90. However the list values never has anything appended to it, so it can never get to the next loop. Here is the code:
def generate_nums(nums): #nums looks like this: [[],[],[]] - which is how it is inputed
for i in range(0, len(nums)):
while True:
values = []
Min = 1
Max = 9
counter = 0
for j in range(0, len(nums[i])):
value = random.randint(0, 1)
values.append(value)
if value == 1:
counter += 1
if counter == 5:
for item in values:
if item == 1:
nums[i].append(random.randint(Min, Max))
else:
nums[i].append(" ")
if Min == 1:
Min = 10
else:
Min += 10
if Max == 79:
Max = 90
else:
Max += 10
break
#Function call
if __name__ == "__main__":
nums = [[],[],[]]
print(generate_nums(nums))
Any help is appreciated, I am only looking to improve my knowledge as I am doing computer science GCSE and I love python and the challenges it presents, though I don't know what to do here.
Thanks!

Having problem with adding iteration into recursion

I was trying to solve a dp problem (checking if given amount can be broken down with given coins with different values, assuming there are infinite number of coins available for each valued coins)
def istrue(coins, amount):
if (amount - coins[0] > 0):
holder = False
while (holder == False and len(coins) != 0):
holder = holder or istrue(coins, amount - coins[0])
if(len(coins) != 0):
coins.pop(0)
return holder
elif (amount - coins[0] < 0):
return False
else:
return True
And was not sure what would be an appropriate way of iterating through the given coins.
Currently, I am having trouble inside the while loop. (If the amount left to break down is bigger than current value of a coin, it moves onto the next coin) But the amount to be break down also goes back a step because I used pop..
Any hints for fixing this? example) coins: [7,3]. amount: 20. -> as it reaches 6 (20-7-7), the index for coins array moves on but also the amount gets backed up a step because I pop()ed it.
You can loop over your coins instead of doing a recursion:
def istrue(coins, amount):
coins.sort(reverse=True)
_, remainder = divmod(amount, coins[0])
coins.pop(0)
for coin in coins:
_, remainder = divmod(remainder, coin)
return not remainder

Issue in the top down approach to the Coin Change (Similar to the 0-1 backpack problem)

I am now working on the Leetcode 322. Coin Change, the question is as following:
You are given an integer array coins representing coins of different
denominations and an integer amount representing a total amount of
money.
Return the fewest number of coins that you need to make up that
amount. If that amount of money cannot be made up by any combination
of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11 Output: 3 Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3 Output: -1
Example 3:
Input: coins = [1], amount = 0 Output: 0
Example 4:
Input: coins = [1], amount = 1 Output: 1
Example 5:
Input: coins = [1], amount = 2 Output: 2
I tried to solve it via the top-down DP with memorization. I set a parameter in the helper function to remember the count.
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
c = set(coins)
dp = [0] * (amount + 1)
def helper(a, count):
if a == 0:
return count
# if a in c:
# return 1 + count
if dp[a] != 0:
return dp[a]
res = math.inf
for coin in c:
if a - coin >= 0 and helper(a-coin, count+1) != -1:
res = min(res, helper(a-coin, count+1))
dp[a] = res if res < math.inf else -1
return dp[a]
return helper(amount, 0)
But it won't pass the case as:
[1,2,5]
100
The result supposes to be 20, but I got 92.
I tried to figure it out the whole afternoon, but not sure where I did wrong. I hope you can give me some suggestion where I went wrong.
Thanks in advance for your help.
!!! THIS IS A COMPLETE SOLUTION !!!
Ok, so here is my solution to this problem (idea explained below):
def solve(lst, amount):
lst = sorted(lst, key=lambda x: x, reverse=True)
cases = []
for seq in [lst[i:] for i in range(len(lst))]:
current_amount = 0
count = 0
for item in seq:
while True:
if current_amount + item == amount:
count += 1
current_amount += item
break
elif current_amount + item > amount:
break
elif current_amount < amount:
count += 1
current_amount += item
if current_amount == amount:
break
if current_amount == amount:
cases.append(count)
if cases:
return min(cases)
return -1
print(solve([1, 2, 5], 100))
print(solve([1, 5, 7, 9], 12))
# 20
# 2
Explanation:
!!! MAIN IDEA
First You have to start with the largest number in the list because it takes the least amount of additions to come the closest or completely become the final amount.
!!!
EDIT
As suggested by #nitinkumarp in comments, previous version (can check edits but why?) failed in some cases as mentioned in the comment, a workaround for that issue is to check all sequences in order, still using the greedy approach but slicing the original list shorter and shorter so that it can also check the correct solution which is 7 + 5, which is 2 coins.
So first thing to do is sort the list from the largest to the smallest number as shown with .sort() function.
Then for each number in that list (for loop starts with the first item in the list so the largest number) put them in a while True loop so that they keep adding to the total until condition is met:
There are 3 conditions:
current amount (from all the additions) plus the current item in the list equals the final amount, in that case increase the count by one and add the current item to total and then break out of the loop
if the current amount + current item in list are bigger than the final amount just break out (this makes sure that no more of such number are added)
the one that will get used the most is the one that checks if the current amount is smaller than the final one, but it is important that they are elif statements because in that case if one statement turns out to be true it doesn't check the rest which is not needed in this case because otherwise it would turn out to be true even if You couldn't add more to the current amount to not exceed the final amount.
this if statement is outside of the while True loop and checks if the final amount is matched when a number 'breaks out' of the while True loop, this is to prevent continuous checking even tho the result would be already achieved.
Then the result get evaluated and if the current amount doesn't match the final print -1 else print the count
This is my solution.
The main idea is to make use of the max value element in the list as much as possible and when it becomes dysfunctional, it is about to remove it from the list and use the new max value element.
class Solution:
def coinChange(self, coins, amount):
result = []
new_amount = amount
while len(coins) > 0:
while new_amount >= max(coins):
new_amount -= max(coins)
result.append(max(coins))
coins.remove(max(coins))
if len(result) == 0:
return 0
if sum(result) != amount:
return -1
return len(result)
Let's test the results;
coins = [2, 5, 4, 1]
amount = 10
s = Solution()
print(s.coinChange(coins=coins, amount=amount))
Output: 2
Because it produced a result list like this; [5, 5]

Having trouble getting my function to meet while loop condition in Python

my goal is to:
Implement the roll_dice function in hog.py. It takes two arguments: a positive integer called num_rolls (which is the number of dice rolls that will be made) and a dice function (A function that simulates a single dice roll outcome). It returns the number of points scored by rolling the dice that number of times in a turn: either the sum of the outcomes or 1.
It returns 1 when any of the dice outcomes is a 1.
When I debug in PyCharm, it says that current_roll = 2, current_value = 4, num_rolls = 5 and total_sum = 4. This leads me to believe that it only went through the loop once since the current_roll should be 5 since the num_rolls is 5. Also, because the total_sum is only the the current_value. I've tried moving around of the variable assignments but nothing has worked.
Could anyone give me any guidance as to why my function is not looping until current_roll is not < num_rolls? Sorry if this is not clear I am a beginner learner. I can offer any clarification
def roll_dice(num_rolls, dice=six_sided):
current_roll = 1
total_sum = 0
current_value = dice()
while current_roll < num_rolls:
current_roll += 1
if current_value == 1 or total_sum == 1:
return total_sum == 1
else:
total_sum = total_sum + current_value
return total_sum
this is what my code is updated to now:
total_sum = 0
current_roll = 0
while current_roll < num_rolls:
current_roll += 1
current_value = dice()
if current_value == 1 or total_sum == 1:
total_sum = 1
return total_sum
else:
total_sum += current_value
return total_sum
I updated my code, but it is still not passing. I added the dice() function into the while loop and changed the total sum = 1. Do you have any idea why it is still not passing?
You are not even using your dice function within the loop. Try to rewrite your code in this way:
def roll_dice(num_rolls, dice=six_sided):
total_sum = 0
rolled_one = False
# roll a dice num_rolls times
for current_roll in range(num_rolls):
# roll a dice
current_value = dice()
# if value=1 then remember what happened
if current_value == 1:
rolled_one = True
# add the value to the sum
total_sum += current_value
# if you previously rolled a 1 then return 1
if rolled_one:
return 1
# otherwise return the final sum
else:
return total_sum
You are returning inside the while loop,
this will terminate the loop.
move your return statement outside the while loop
Edit:
Move the dice function call within the while loop.
In the current state of your code it will only roll the dice once, and then check that roll num_rolls times.
also you are returning total_sum == 1 this will return True or False not sure if this is intended

Probability Dice Game in Python with two dices

I want to interate 1000 times over the following function to find out if you win or loose money in this game.
The game is designed as such that you throw a pair of dice and get money back or loose money. Let's say we start with 5 coins.
Throwing a 12 yields 1.5 coins.
Throwing an 11 yields 1 coins.
Throwing a 10 yields 0.5 coins.
Throwing a 9,8 or 7 yields nothing.
Throwing a 6,5,4,3,2 or 1 deducts 0.5 coins from your amount of coins.
This is what my implementation looks like so far:
def luckCalc():
amount = 5
# if 12 then 1/36 chance
if random.randrange(1,7) == 6 and random.randrange(1,7) == 6:
amount = amount + 1.5
# if 11 then 2/36 chance
elif (random.randrange(1,7) == 5 and random.randrange(1,7) == 6) or (random.randrange(1,7) == 6 and random.randrange(1,7) == 5):
amount = amount + 1
# if 10 then 3/36 chance
elif (random.randrange(1,7) == 5 and random.randrange(1,7) == 5) or (random.randrange(1,7) == 4 and random.randrange(1,7) == 6) or (random.randrange(1,7) == 6 and random.randrange(1,7) == 4):
amount = amount + 0.5
# if 9,8,7
# 4/36 + 5/36 + 6/36 chance
# 1+6, 2+5, 3+4, 4+3, 5+2, 6+1 chance
# 2+6, 3+5, 4+4, 5+3, 6+2 chance
# 3+6, 4+5, 5+4, 6+3 chance
# then no change in amount
# if 6,5,4,3,2,1
# chances...
# then amount -0.5
return amount
# Iterate over the dice throwing simulator and calculate total
total = 0.0
for a in range(1000):
total = total + luckCalc()
print (total)
I stopped coding towards the end of the function, because I recognised that there must be a more elegant solution on how to achieve this. Any interesting suggestions, what is this Monte Carlo I keep hearing about?
Each time you call random.randrange(1,7), you generate a new random number. Since you're testing a single "turn", roll twice:
def roll_die():
return random.randrange(1, 7)
total = roll_die() + roll_die()
And see if the sum is in a range:
def play_turn():
total = roll_die() + roll_die()
if total == 12:
return 1.5
elif total == 11:
return 1.0
elif total == 10:
return 0.5
elif total <= 6:
return -0.5
else: # total is 7, 8, or 9
return 0
Here's the result of 100,000 rounds:
>>> from collections import Counter
>>> counts = Counter(play_turn() for i in xrange(100000))
>>> counts
Counter({-0.5: 41823, 0: 41545, 0.5: 8361, 1.0: 5521, 1.5: 2750})
>>> probabilities = {score: count / 100000.0 for score, count in counts.items()}
>>> probabilities
{-0.5: 0.41823, 0: 0.41545, 0.5: 0.08361, 1.0: 0.05521, 1.5: 0.0275}
You can actually roll (ha!) everything you are doing into a single function:
from random import randrange
def play_game(rolls=1000, amount=5, n=6):
"""Play game 'rolls' times, starting with 'amount' on 'n'-sided dice."""
for i in range(rolls):
roll = randrange(1, n+1) + randrange(1, n+1)
if roll == 12:
amount += 1.5
elif roll == 11:
amount += 1
elif roll == 10:
amount += 0.5
elif roll < 7:
amount -= 0.5
return amount
I notice a few things in your code. First, for the 6-1 cases you're not actually subtracting 0.5 from the amount. Second, since you don't pass in the initial amount each loop you're adding between 5 and 6.5 to your total, which makes the total pretty pointless.
A more effective total would be to pass in the amount each time:
def luckCalc( amount ):
And then for your loop:
total = 5.0
for a in range(1000):
total = luckCalc(total)
Blender's answer, which just posted as I was writing this, is a great way to simplify your main function.
I personally like setting up my results table as an array (or a dictionary, but this suited my purpose better since every result was one of a small number of possible integers), with the index of each dice roll set to the value of the resulting change. See below.
import random
def luckCalc(coins=5):
diceroll = random.randint(1,6)+random.randint(1,6) #roll them bones
#here's that table I was talking about....
results_table = ['index 0 is blank',"you can't roll a one on two dice",-.5,-.5,-.5,-.5,-.5,0,0,0,.5,1,1.5]
coins += results_table[diceroll] #changes your coins value based on your roll (as an index of results_table)
if results_table[diceroll] > 0: #change the string if your result was + or -
result = "gained {}".format(results_table[diceroll])
else:
result = "lost {}".format(results_table[diceroll]*-1)
print("You {} coins, putting you at {}".format(result,coins)) #report back to the user
return coins #this is how you save your output
#CONSTANTS GO HERE -- YOU CAN CHANGE THESE TO CHANGE YOUR PROGRAM
STARTING_COINS = 5
HOW_MANY_ITERATIONS = 1000
#this way we don't modify a constant
coins = STARTING_COINS
#do it how many times?
for _ in range(HOW_MANY_ITERATIONS): #oh yeah that many times
coins = luckCalc(coins) #runs the function and saves the result back to coins
#report to the user your final result.
print("After {} rolls, your final total is {}".format(HOW_MANY_ITERATIONS,coins))

Categories