How can we change this recursive function to "for iteration"?.....
Note: Greed algorithms should not be used. Greedy algorithms are less accurate.
Reason to change : To increase the efficiency of a function by changing to a dynamic algorithm
What I've tried:
# this code is trash
for i in range(1,m+1):
n1=m-coins[i]
for i in range(1,m+1):
n2=m-coins[i]
return min(n1,n2)
while n1==0:
i=i+1
n1=m-coins[i]
return n1
Besides this, I tried using dictionary and combination, but I forgot because I thought it wouldn't work.
How the function behaves : It is a function that takes a list of coins and a value of m and makes m==0.
n1 means moving on without using coins[0].
n2 means using coins[0] as a necessity and moving on to the next level.
If I had a list of [5,4,2,1] and a value of 10 m, I would recurs the first n1=[4,2,1],10 and the first n2=[5,4,2,1],10.
coins =[50,40,20,10,5,4,2,1]
m = 80
def coin_count(coins, m):
if m > 0:
while len(coins) > 0 and m < coins[0]:
coins = coins[1:]
#Below is the part I want to change.
if coins[0] > 1:
n1=coin_count(coins[1:],m)
n2=coin_count(coins,m-coins[0])+1
return min(n1,n2)
else: # coins[0] == 1
return m
#Above is the part I want to change
else: # m == 0
return 0
Here is my solution to your function using a while loop. It returns the smallest possible list of coins that sums up to m - I suppose this is what you were looking for?
How it works is that in each while loop iteration, it takes the current largest coin and checks if the remainder of m is divisible by that coin, adding the number of coins needed and setting m to the remainder
def coin_count(coins, m):
coins = sorted(coins, reverse=True)
out = []
while m > 0:
cur_coin = coins.pop(0)
out.extend([cur_coin] * (m // cur_coin))
m %= cur_coin
return out
NB: If the input coins are always sorted in descending order, you can remove the first line.
Example:
coins = [50, 40, 20, 10, 5, 4, 2, 1]
m = 128
print(coin_count(coins, m))
[50, 50, 20, 5, 2, 1]
Related
This is the description of the problem I am trying to solve.
Hey, I Already Did That!
Commander Lambda uses an automated algorithm to assign minions randomly to tasks, in order to keep minions on their toes. But you've noticed a flaw in the algorithm -- it eventually loops back on itself, so that instead of assigning new minions as it iterates, it gets stuck in a cycle of values so that the same minions end up doing the same tasks over and over again. You think proving this to Commander Lambda will help you make a case for your next promotion.
You have worked out that the algorithm has the following process:
Start with a random minion ID n, which is a nonnegative integer of length k in base b
Define x and y as integers of length k. x has the digits of n in descending order, and y has the digits of n in ascending order
Define z = x - y. Add leading zeros to z to maintain length k if necessary
Assign n = z to get the next minion ID, and go back to step 2
For example, given minion ID n = 1211, k = 4, b = 10, then x = 2111, y = 1112 and z = 2111 - 1112 = 0999. Then the next minion ID will be n = 0999 and the algorithm iterates again: x = 9990, y = 0999 and z = 9990 - 0999 = 8991, and so on.
Depending on the values of n, k (derived from n), and b, at some point the algorithm reaches a cycle, such as by reaching a constant value. For example, starting with n = 210022, k = 6, b = 3, the algorithm will reach the cycle of values [210111, 122221, 102212] and it will stay in this cycle no matter how many times it continues iterating. Starting with n = 1211, the routine will reach the integer 6174, and since 7641 - 1467 is 6174, it will stay as that value no matter how many times it iterates.
Given a minion ID as a string n representing a nonnegative integer of length k in base b, where 2 <= k <= 9 and 2 <= b <= 10, write a function solution(n, b) which returns the length of the ending cycle of the algorithm above starting with n. For instance, in the example above, solution(210022, 3) would return 3, since iterating on 102212 would return to 210111 when done in base 3. If the algorithm reaches a constant, such as 0, then the length is 1.
My solution isn't passing 5 of the 10 test cases for the challenge. I don't understand if there's a problem with my code, as it's performing exactly as the problem asked to solve it, or if it's inefficient.
Here's my code for the problem. I have commented it for easier understanding.
def convert_to_any_base(num, b): # returns id after converting back to the original base as string
digits = []
while(num/b != 0):
digits.append(str(num % b))
num //= b
result = ''.join(digits[::-1])
return result
def solution(n, b):
minion_id_list = [] #list storing all occurrences of the minion id's
k = len(n)
while n not in minion_id_list: # until the minion id repeats
minion_id_list.append(n) # adds the id to the list
x = ''.join(sorted(n, reverse = True)) # gives x in descending order
y = x[::-1] # gives y in ascending order
if b == 10: # if number is already a decimal
n = str(int(x) - int(y)) # just calculate the difference
else:
n = int(x, b) - int(y, b) # else convert to decimal and, calculate difference
n = convert_to_any_base(n, b) # then convert it back to the given base
n = (k-len(n)) * '0' + n # adds the zeroes in front to maintain the id length
if int(n) == 0: # for the case that it reaches a constant, return 1
return 1
return len(minion_id_list[minion_id_list.index(n):]) # return length of the repeated id from
# first occurrence to the end of the list
I have been trying this problem for quite a while and still don't understand what's wrong with it. Any help will be appreciated.
I am learning Python and using it to work thru a challenge found in Project Euler. Unfortunately, I cannot seem to get around this problem.
The problem:
Even Fibonacci numbers
Each new term in the Fibonacci sequence is generated by adding the
previous two terms. By starting with 1 and 2, the first 10 terms will
be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not
exceed four million, find the sum of the even-valued terms.
I created a for loop that adds the second to last element and the last element from the list x:
x = [1,2]
for i in x:
second_to_last = x[-2]
running_sum = i + second_to_last
If you run the above, you get 3. I am looking to add this new element back to the original list, x, and repeat the process. However, each time I try to use the append() function, the program crashes and keeps on running without stopping. I tried to use a while loop to stop this, but that was a complete failure. Why am I not able to add or append() the new element (running_sum) back to the original list (x)?
UPDATE:
I did arrive at the solution (4613732), but I the work to getting there did not seem efficient. Here is my solution:
while len(x) in range(1,32):
for i in x:
second_to_last = x[-2]
running_sum = i + second_to_last
x.append(running_sum)
print(x)
new_x = []
for i in x:
if i%2 == 0:
new_x.append(i)
sum(new_x)
I did have to check the range to see visually whether I did not exceed 4 million. But as I said, the process I took was not efficient.
If you keep adding elements to a list while iterating over that list, the iteration will never finish.
You will need some other criterion to abort the loop - for example, in this case
if running_sum > 4000000:
break
would work.
(Note that you don't strictly speaking need a list at all here; I'd suggest experimenting a bit with it.)
Here are two different ways to solve this. One of them builds the whole list, then sums the even elements. The other one only keeps the last two elements, without making the whole list.
fib = [1,2]
while fib[-1] < 4000000:
fib.append(fib[-2]+fib[-1])
# Get rid of the last one, since it was over the limit.
fib.pop(-1)
print( sum(i for i in fib if i % 2 == 0) )
fib = (1,2)
sumx = 2
while True:
nxt = fib[0]+fib[1]
if nxt >= 4000000:
break
if nxt % 2 == 0:
sumx += nxt
fib = (fib[1],nxt)
print(sumx)
I don't answer your question about list modification but the solution for your problem:
def sum_even_number_fibonacci(limit):
n0 = 0 # Since we don't care about index (n-th), we can use n0 = 0 or 1
n1 = 1
even_number_sum = 0
while n1 <= limit:
if n1 % 2 == 0:
even_number_sum += n1
n2 = n0 + n1
# Only store the last two number of the Fibonacci sequence to calculate the next one
n0 = n1
n1 = n2
return even_number_sum
sum_even_number_fibonacci(4_000_000)
Assume there are two variables, k and m, each already associated with a positive integer value and further assume that k's value is smaller than m's. Write the code necessary to compute the number of perfect squares between k and m. (A perfect square is an integer like 9, 16, 25, 36 that is equal to the square of another integer (in this case 3*3, 4*4, 5*5, 6*6 respectively).) Associate the number you compute with the variable q. For example, if k and m had the values 10 and 40 respectively, you would assign 3 to q because between 10 and 40 there are these perfect squares: 16, 25, and 36,.
**If I want to count the numbers between 16 and 100( 5,6,7,8,9 =makes 5)and write code in terms of with i and j, my code would be as follows but something goes wrong. I want to get the result,5 at last. how can I correct it?
k=16
m=100
i=0
j=0
q1=0
q2=0
while j**2 <m:
q2=q2+1
while i**2 <k:
q1=q1+1
i=i+1
j=j+1
print(q2-q1)
Your probably don't want to loop for this. If k and m are very far apart it will take a long time.
Given k < m, you want to compute how many integers l such that k < l^2 < m. The smallest possible such integer is floor( sqrt(k) +1 ) and the largest possible such integer is ceil(sqrt(m)-1). The number of such integers is:
import math
def sq_between(k,m):
return math.ceil(m**0.5-1) - math.floor(k**0.5+1) +1
This allows for
sq_between(16,100)
yielding:
5
Here is another version of your function that seems to do to what you ask for.
k = 16
m = 100
perfect_squares = []
for i in range(m):
if i**2 < k:
continue
if i**2 > m:
break
perfect_squares.append(i**2)
print(perfect_squares)
You code is mixing up everything in the second while loop. If you explain a bit further what you are trying to do there, I will probably be able to explain why your idea is not working.
I would change your code as follows in order to make it work:
k = 10
m = 40
i = 0
q = 0
while i ** 2 < m:
if i ** 2 > k:
print(i)
q += 1
i += 1
print (q)
By utilizing the fact that each square number can get expressed via square = sum from i = 1 to n (2 * i + 1) there is an easy way of speedup the above algorithm - but the algorithm will become much longer then ...
I was participating in a python challenge in codewars website. I encountered the following challenge:
Divisors of 42 are : 1, 2, 3, 6, 7, 14, 21, 42. These divisors squared are: 1, 4, 9, 36, 49, 196, 441, 1764. The sum of the squared divisors is 2500 which is 50 * 50, a square!
Given two integers m, n (1 <= m <= n) we want to find all integers between m and n whose sum of squared divisors is itself a square. 42 is such a number.
The result will be an array of arrays, each subarray having two elements, first the number whose squared divisors is a square and then the sum of the squared divisors.
The output should be:
list_squared(1, 250) --> [[1, 1], [42, 2500], [246, 84100]]
list_squared(42, 250) --> [[42, 2500], [246, 84100]]
list_squared(250, 500) --> [[287, 84100]]
I have written following code with two additional functions: one corresponding to determine all factors of a number and other checking if a number is perfect square or not.
Function to determine all factors:
def fact(m):
return [i for i in range(1,m+1) if m%i == 0]
Function to check if a number is perfect square and return 0 if it is not otherwise return square root
def square_root(x):
ans = 0
while ans < x // 2 + 1:
ans = ans + 1
if ans*ans == x:
return ans
break;
return 0
Function where the desired result is calculated
def list_squared(m, n):
# your code
fac=[]
for i in range(m,n+1):
sq_sum = sum(list(map(lambda x: x**2,fact(i))))
if square_root(sq_sum) != 0:
fac.append([i,sq_sum])
return fac
This code gives me the correct result, however it is too long. I was able to pass all the test results but it took me around 6000 ms. When I attempted to submit the code, the web submission returns that the algorithm is inefficient and it took more than 1200 ms which is the maximum.
I would highly appreciate if anyone can point to a better algorithm for this.
There are several optimizations to your code but the biggest one is to stop when ans*ans becomes bigger than x here:
def square_root(x):
ans = 0
while True:
ans += 1
sqans = ans*ans
if sqans == x:
return ans
elif sqans > x:
return 0
The condition in the while can be removed, since now the test is done on the square value.
with that optimization, I drop from 8 seconds to 0.07 seconds with the 250, 500 case.
But that's stil not satisfactory. In general, algorithms containing a condition to break or return are at least O(n) and even if you can save time, the complexity is too high.
You can do better by simply checking the square of the rounded square root:
def square_root(x):
ans = int(x**0.5 + 0.5) # rounded just in case it goes below the actual value (float inaccuracy)
sqans = ans*ans
return 0 if sqans !=x else x
I divide the execution time by further 2 with that (confirmed by Optimized way to find if a number is a perfect square)
Aside (that doesn't speed up that much but worth mentionning):
no need to convert map to list in sum:
sq_sum = sum(map(lambda x: x**2,fact(i)))
Also fact could avoid looping to the max number. Loop to the max number divided by 2 and add the max number to the list is equivalent. No more divisors exist above max number / 2
def fact(m):
return [i for i in range(1,m//2+1) if m%i == 0] + [m]
Final edit: this is still slow because of the list comprehension used in fact. I could cut the time drastically by using a generator instead and add m*m outside it:
def sqfact(m):
return (i*i for i in range(1,m//2+1) if m%i == 0)
final code, now runs so fast I get 0 seconds.
def sqfact(m):
return (i*i for i in range(1,m//2+1) if m%i == 0)
def square_root(x):
ans = int(x**0.5 + 0.5)
return 0 if ans*ans !=x else x
def list_squared(m, n):
# your code
fac=[]
for i in range(m,n+1):
sq_sum = sum(sqfact(i)) + i*i # add i square outside
if square_root(sq_sum):
fac.append([i,sq_sum])
return fac
I have updated the fact function which was very inefficient. Now, rather than iterating to full value of m to find its factors, I am only going up to sqrt(m). This has reduced the run time immensely. The logic behind this is trivial so I am not elaborating. Following is the new code which worked for me.
def fact(m):
#determining the lower factors i.e., smaller than sqrt(m)
fac = [i for i in range(1, int(m**0.5) + 1) if m%i == 0]
#determining the higher factors i.e., larger than sqrt(m)
fac = fac + [m//i for i in range(1, int(m**0.5) + 1) if m%i == 0]
return sorted(list(set(fac))) #in order to get rid of duplicate factors
I'm a stumped on how to speed up my algorithm which sums multiples in a given range. This is for a problem on codewars.com here is a link to the problem
codewars link
Here's the code and i'll explain what's going on in the bottom
import itertools
def solution(number):
return multiples(3, number) + multiples(5, number) - multiples(15, number)
def multiples(m, count):
l = 0
for i in itertools.count(m, m):
if i < count:
l += i
else:
break
return l
print solution(50000000) #takes 41.8 seconds
#one of the testers takes 50000000000000000000000000000000000000000 as input
# def multiples(m, count):
# l = 0
# for i in xrange(m,count ,m):
# l += i
# return l
so basically the problem ask the user return the sum of all the multiples of 3 and 5 within a number. Here are the testers.
test.assert_equals(solution(10), 23)
test.assert_equals(solution(20), 78)
test.assert_equals(solution(100), 2318)
test.assert_equals(solution(200), 9168)
test.assert_equals(solution(1000), 233168)
test.assert_equals(solution(10000), 23331668)
my program has no problem getting the right answer. The problem arises when the input is large. When pass in a number like 50000000 it takes over 40 seconds to return the answer. One of the inputs i'm asked to take is 50000000000000000000000000000000000000000, which a is huge number. That's also the reason why i'm using itertools.count() I tried using xrange in my first attempt but range can't handle numbers larger than a c type long. I know the slowest part the problem is the multiples method...yet it is still faster then my first attempt using list comprehension and checking whether i % 3 == 0 or i % 5 == 0, any ideas guys?
This solution should be faster for large numbers.
def solution(number):
number -= 1
a, b, c = number // 3, number // 5, number // 15
asum, bsum, csum = a*(a+1) // 2, b*(b+1) // 2, c*(c+1) // 2
return 3*asum + 5*bsum - 15*csum
Explanation:
Take any sequence from 1 to n:
1, 2, 3, 4, ..., n
And it's sum will always be given by the formula n(n+1)/2. This can be proven easily if you consider that the expression (1 + n) / 2 is just a shortcut for computing the average, or Arithmetic mean of this particular sequence of numbers. Because average(S) = sum(S) / length(S), if you take the average of any sequence of numbers and multiply it by the length of the sequence, you get the sum of the sequence.
If we're given a number n, and we want the sum of the multiples of some given k up to n, including n, we want to find the summation:
k + 2k + 3k + 4k + ... xk
where xk is the highest multiple of k that is less than or equal to n. Now notice that this summation can be factored into:
k(1 + 2 + 3 + 4 + ... + x)
We are given k already, so now all we need to find is x. If x is defined to be the highest number you can multiply k by to get a natural number less than or equal to n, then we can get the number x by using Python's integer division:
n // k == x
Once we find x, we can find the sum of the multiples of any given k up to a given n using previous formulas:
k(x(x+1)/2)
Our three given k's are 3, 5, and 15.
We find our x's in this line:
a, b, c = number // 3, number // 5, number // 15
Compute the summations of their multiples up to n in this line:
asum, bsum, csum = a*(a+1) // 2, b*(b+1) // 2, c*(c+1) // 2
And finally, multiply their summations by k in this line:
return 3*asum + 5*bsum - 15*csum
And we have our answer!