Power Sum Recursive Algorithm - ruby

I'm working on an algorithm where we're given two inputs, a total amount, and a power value. We must find the total number of unique combinations of numbers to the power parameter that sum up to the total amount.
For example:
Given amount = 10 and power = 2, there is only one unique solution:
(1^2) + (3^2) = 10
(Problem comes from here: https://www.hackerrank.com/challenges/the-power-sum)
Here's my algorithm thus far:
def count_unique_combos(total, candidate, power)
return -1 if total < 0 || candidate > total # this means impossible to continue
return 1 if total == 0 # arrived at our goal
num_ways = 0
# all the ways to get the total amount, if we use candidate ** power
with_candidate = count_unique_combos(total - candidate ** power, candidate + 1, power)
num_ways += with_candidate if with_candidate != -1
# all the ways to get the total amount without using the candidate.
without_candidate = count_unique_combos(total, candidate + 1, power)
num_ways += without_candidate if without_candidate != -1
num_ways
end
Here's what I'm confused about. I've read a lot about the recursive algorithm's leap of faith, where you assume that you have the function working for N-1 inputs, and you just need to make it work for input size N and put in the correct base cases.
The bases cases seem reasonable to me, as does the recursive relationship (get all unique combos with this number, get all of them without this number).
However, my output is incorrect. For amount = 10 and power = 2, my resulting value is zero. Does anyone know where I'm not approaching this logically?

Try it with swapping your base cases
return 1 if total == 0 # arrived at our goal
return -1 if total < 0 || candidate > total # this means impossible to continue
when total == 0 any candidate you pass in (since you only ever increment candidate) is going to be candidate > total and you'll break out with a -1 before you check if you've reached your positive base case.
When you swap them (using tadman's test cases, for ease of comparison)
count_unique_combos(10, 1, 2)
# => 1
count_unique_combos(100, 1, 2)
# => 3
count_unique_combos(100, 1, 3)
# => 1

When you're talking about sets of numbers, especially when it pertains to permutations and/or combinations, it's a lot easier to lean on the core Ruby functions like combination:
def power_sum(total, power)
set = (1..total).to_a
(1..set.length).flat_map do |size|
set.combination(size).to_a
end.select do |numbers|
numbers.inject(0) { |s, n| s + n ** power } == total
end
end
Then based on the test cases:
power_sum(10, 2)
# => [[1, 3]]
power_sum(100, 2)
# => [[10], [6, 8], [1, 3, 4, 5, 7]]
power_sum(100, 3)
# => [[1, 2, 3, 4]]
If you only care about how many, call .length on the end.
A recursive approach is possible here, but the way you're tackling it doesn't seem to handle the combinations properly. You'll need to have two different recursive method that works with N-sized subsets.

Related

Execution Timed Out (12000 ms): How can I optimize this simple kata to run faster?

I'm practicing my coding chops after a long break and ran into this kata on CodeWars
With an input of numbers in an array, return the sums of its parts. So for example:
def parts_sums(ls)
sums = []
until ls.size == 0
sums << ls.inject(:+)
ls.shift
end
sums << 0
end
######### INPUT #######
parts_sums([0, 1, 3, 6, 10])
######### EXPECTED OUTPUT ######
[20, 20, 19, 16, 10, 0]
0 + 1 + 3 + 6 + 10 = 20
1 + 6 + 3 + 10 = 20
3 + 6 + 10 = 19
6 + 10 = 16
10 = 10
0 = 0
My solution solves the kata, however once I reach arrays of around 30,000+ my solution takes too long to solve.
So my question is to the community, how would I even attempt to make this go faster. I know that recursion is usually slow, and that for loops and its variants are usually sufficient to get the job done. What happens when that fails? What are some things to try to make my code above faster?
I'm looking for some advice and some examples if anyone has any. Appreciate the input. Thanks.
def parts_sums(ls)
ls.each_with_object([ls.sum]) { |n,arr| arr << arr.last - n }
end
parts_sums([0, 1, 3, 6, 10])
#=> [20, 20, 19, 16, 10, 0]
The issue with the code is that you are performing an inject on every iteration of your loop, which is unnecessarily slow.
You only need to sum the elements of the array once, outside of any loop. Once you have that sum, you can iterate through the elements of the array and perform a constant time subtraction from the current sum and push it into the sums array.
def part_sums(ls)
sum = ls.inject(:+)
sums = [sum]
ls.each do |val|
sum -= val
sums << sum
end
sums
end
There is also no need to shift, if you iterate through the array with the each iterator or keep a counter and use a while loop.
This version of the function runs much faster:
def parts_sums_2(ls)
sums = []
last_sum = 0
(ls.length - 1).downto(0).each do |i|
last_sum += ls[i]
sums.prepend last_sum
end
sums + [0]
end
The key here is going backwards through the array - starting with the smallest sum (only the last element). Each subsequent step moves one index towards the beginning, and adds that value to the previous sum.
Since the problem statement requires you to shift each step, your result must have the largest sums at the beginning, even though these are the last ones to be computed. This is why my code uses prepend rather than push.
This is O(N) time complexity instead of O(N^2), which is an order of magnitude difference.
With 100_000 inputs, your original function took 7.040443 seconds, while mine here took 0.000008 seconds
Also in general you should try to avoid mutating the input to your methods (as you were doing with shift).

JAVA - Recursive function to determine all prime factors of n

What I have problems understanding is how can I write a recursive method that adds to the array, if I can only have n as parameter to my function.
You have two cases: base case and recursion case. For your problem, the high-level logic looks like this:
if n is prime
return array(n) // return a one-element array
else {
find a prime divisor, p
// return an array of p and the factorisation of n/p
return array(p, FACTORIZATION(n/p) )
}
Does that get you moving? You'll need to know how to make and append to arrays in your chosen language, but those are implementation details.
It would look either like:
def factorize(n):
factors= list()
found= False
t= 2
while t*t <= n and not found:
while (n % t) == 0:
# divisible by 2
factors.append(t)
found= True
n//= t
t+= 1
if found:
factors.extend(factorize(n))
else:
factors.append(n)
return factors
factorize(3*5*5*7*7*31*101)
# --> [3, 5, 5, 7, 7, 31, 101]
Which is a naiive apporoach, to keep it simple. Or you allow some more (named) arguments to your recursive function, which would also allow passing a list. Like:
def factorize2(n, result=None, t=2):
if result:
factors= result
else:
factors= list()
found= False
while t*t <= n and not found:
while (n % t) == 0:
factors.append(t)
found= True
n//= t
t+= 1
if found:
factorize2(n, factors, t+1)
else:
factors.append(n)
return factors
The basic difference is, that here you reuse the list the top level function created. This way you might give the garbabge collector a little less work (though in case of a factorization function this probably doesn't make much of a difference, but in other cases I think it does). The second point is, that you already tested some factors and don't have to retest them. This is why I pass t.
Of course this is still naiive. You can easily improve the performance, by avoiding the t*t < n check in each iteration and by just testing t if t is -1/1 mod 6 and so on.
Another approach to have in your toolbox is to not return an array, but rather a linked list. That is a data structure where each piece of data links to the next, links to the next, and so on. Factorization doesn't really show the power of it, but here it is anyways:
def factorize(n, start=2):
i = start
while i < n:
if n % i == 0:
return [i, factorize(n//i, i)]
elif n < i*i:
break
i = i + 1
if 1 < i:
return [n, None]
else:
return None
print(factorize(3*5*5*7*7*31*101)) # [3, [5, [5, [7, [7, [31, [101, None]]]]]]]
The win with this approach is that it does not modify the returned data structure. So if you're doing something like searching for an optimal path through a graph, you can track multiple next moves without conflict. I find this particularly useful when modifying dynamic programming algorithms to actually find the best solution, rather than to report how good it is.
The one difficulty is that you wind up with a nested data structure. But you can always flatten it as follows:
def flatten_linked_list (ll):
answer = []
while ll is not None:
answer.append(ll[0])
ll = ll[1]
return answer
# prints [3, 5, 5, 7, 7, 31, 101]
print(flatten_linked_list( factorize(3*5*5*7*7*31*101) ))
Here are two recursive methods. The first has one parameter and uses a while loop to find a divisor, then uses divide and conquer to recursively query the factors for each of the two results of that division. (This method is more of an exercise since we can easily do this much more efficiently.) The second relies on a second parameter as a pointer to the current prime factor, which allows for a much more efficient direct enumeration.
JavaScript code:
function f(n){
let a = ~~Math.sqrt(n)
while (n % a)
a--
if (a < 2)
return n == 1 ? [] : [n]
let b = n / a
let [fa, fb] = [f(a), f(b)]
return (fa.length > 1 ? fa : [a]).concat(
fb.length > 1 ? fb : [b])
}
function g(n, d=2){
if (n % d && d*d < n)
return g(n, d == 2 ? 3 : d + 2)
else if (d*d <= n)
return [d].concat(g(n / d, d))
return n == 1 ? [] : [n]
}
console.log(f(567))
console.log(g(12345))

Struggling with recursive base case

I've spent a while on the following algorithm:
You are given coins of different denominations and a total amount of
money amount. Write a function to compute 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.
Example 1: coins = [1, 2, 5], amount = 11 return 3 (11 = 5 + 5 + 1)
Example 2: coins = [2], amount = 3 return -1.
Note: You may assume that you have an infinite number of each kind of
coin.
This is likely not the most efficient way to solve the problem, but I figured I can solve it by trying every coin and launching a new function per attempt, where the new function call has the updated amount. This would launch N function calls per coin... but I'll deal with that later.
Right now I'm dealing with the following issue: often when making recursive calls, I'm unable to properly code in a base case. For example, in this problem we have to return -1 if the amount of money cannot be made up by any combination of the coins. However, I also need to count up the fewest number of coins. So I figured I'd take a min variable and call 1 + new_func_call.
However, when this new_func_call ends up not working out, it passes up a -1 to the recursive call stack, which ends up making min zero instead. I'm not sure how to adjust this-- I've tried varying my code in different ways but perhaps I'm having a conceptual issue. I know why it's happening-- just don't know how to deal with it.
Sample input:
Coins: [2]
Amount: 3
My output: 0
Correct output: -1
Code:
def coin_change(coins, amount)
coin_count(coins, amount, coins.min)
end
def coin_count(coins, amount, min_coin)
with_coin = min = 1.0/0
return 0 if amount == 0
return -1 if amount < min_coin
i = 0
while i < coins.length
with_coin = 1 + coin_count(coins, amount - coins[i], min) if amount - coins[i] >= 0
min = [min, with_coin].min
i += 1
end
min
end
Right now I'm dealing with the following issue: often when making recursive calls, I'm unable to properly code in a base case. For example, in this problem we have to return -1 if the amount of money cannot be made up by any combination of the coins. However, I also need to count up the fewest number of coins.
Well you sort of have two base cases here
If the amount state variable is zero, we are done counting, so return the count
If we run out of coins (xs) to count with and still didn't reach a zero-amount, then return -1
Otherwise we have the two recursion cases
oops: amount is less than 0 meaning the last coin (x) subtracted was too big – rewind and recurse without using this coin
default case: add 1 to count, subtract the coin (x) from amount, and recurse using the same set of coins (xs)
The only requirement for this to work is that the coins are first sorted in descending order
OK, so all of this is easily encoded in Ruby using an auxiliary helper (aux) to hold our state variables. Remember to initialize with a count of 0 and ensure that xs is sorted in descending order. - Note the sorting only happens once – not once per recursion
def fewest_coins amount, xs
def aux count, amount, (x,*xs)
if amount.zero?
count
elsif x.nil?
-1
elsif amount < 0
aux (count - 1), (amount + x), xs
else
aux (count + 1), (amount - x), [x, *xs]
end
end
aux 0, amount, xs.sort { |a,b| b <=> a }
end
fewest_coins 11, [1, 5, 2] # => 3
fewest_coins 2, [3] # => -1
fewest_coins 100, [1, 25, 10, 5] # => 4
Check your understanding
As an exercise, modify fewest_coins to output an array of coins that makes up the answer
# for example
fewest_coins 199, [1, 5, 10, 25, 50]
# => [50, 50, 50, 25, 10, 10, 1, 1, 1, 1]
You could do that as follows.
def count_ways(cents, coins)
if coins.size == 1
return (cents % coins.first) == 0 ? [cents/coins.first] : nil
end
coin, *remaining_coins = coins
(0..cents/coin).each_with_object([]) { |n, arr|
count_ways(cents-n*coin, remaining_coins).each { |a| arr << [n, *a] } }
end
def fewest(cents, coins)
count_ways(cents, coins)&.map(&:sum)&.min
end
fewest(11, [5,2,1])
#=> 3
fewest(199, [25,10,5,1])
#=> 13 (Let me guess: 7 quarters, 2 dimes, 4 pennies)
fewest(2, [3])
#=> nil
require 'time'
t = Time.now
fewest(2835, [25,10,5,1])
#=> 114
Time.now - t
#=> 7.6961 (seconds)
I took count_ways from my answer here.
The two &'s followed by . are Ruby's safe navigation operator, which was introduced in Ruby v2.3.0. Array#sum (and Enumerable#sum) first appeared in Ruby v2.4.0.
This question already has a really good answer that shows you exactly how to solve your problem, but I wanted to point out what was actually happening with your algorithm, so you know why it wasn't working for you.
Your first problem is that
coin_count(coins, amount - coins[i], min)
should be
coin_count(coins, amount - coins[i], coins.min)
Instead of passing along the smallest coin, you were passing along your min value, which you had set to Infinity, which made this statement checking if the amount was smaller than the smallest coin:
return -1 if amount < min_coin
actually check if the amount was smaller than infinity, which meant your coin_count is always returning -1. Which leads to the second problem:
1 + coin_count(coins, amount - coins[i], min)
#1 + -1 = 0
The frustrating thing about using -1 as an error in recursive programming is that -1 is an otherwise valid number and frequently causes logic problems. I would avoid using it entirely, but if your prompt or spec forces you to return it, i'd use it only at the last second. try:
def coin_change(coins, amount)
result = coin_count(coins, amount, coins.min)
return -1 if result == 1/0.0
return result
end
def coin_count(coins, amount, min_coin)
with_coin = min = 1.0/0
return 0 if amount == 0
return 1/0.0 if amount < min_coin
i = 0
while i < coins.length
with_coin = 1 + coin_count(coins, amount - coins[i], coins.min) if amount - coins[i] >= 0
min = [min, with_coin].min
i += 1
end
min
end
I changed your error number from -1 to infinity, which essentially makes your algorithm ignore invalid permutations since they're always sorted out by your .min(). the only way your function would return infinity in this case is if it were the smallest number returned, which only happens when there are no valid permutations. Then in fewest_coins I set it to check for infinity and return -1 instead.
Oh and by the way, there's a much easier way to loop through things in ruby:
coins.each do |coin|
with_coin = 1 + coin_count(coins, amount - coin, coins.min) if amount - coin >= 0
min = [min, with_coin].min
end
This definitely won’t be a smartest approach, it’s not the best performant one, and it might be time consuming for huge amounts, but it’s how I would do it in ruby:
def get coins, amount
coins = coins.sort
max = amount / coins.first + 1
(1..max).detect do |i|
result = coins.repeated_permutation(i).detect do |e|
e.reduce(:+) == amount
end
break result if result
end || -1
end
get [1, 2, 5], 11
#⇒ [1, 5, 5]
get [2], 3
#⇒ -1

Finding smallest prime factor

I am trying to create a function that returns the smallest prime factor of a given number:
require 'prime'
def findSmallestPrimeFactor(number)
return 2 if number.even?
return number if Prime.prime? number
arrayOfFactors = (1..number).collect { |n| n if number % n == 0 }.compact
arrayOfFactors.each { |n| arrayOfFactors.pop(n) unless Prime.prime? n }
return arrayOfFactors[0]
end
findSmallestPrimeFactor(13333) should return 67 but instead returns 1, which should not be happening since 1 should be removed from arrayOfFactors during line 7, as Prime.prime? 1 returns false
It sometimes returns nothing:
puts findSmallestPrimeFactor(13335) # => returns empty line
This issue only occurs when working with a number that is not even and is not prime, i.e lines 4 and 5 are ignored.
Also, when this is finished I will be passing some very large numbers through it. Is there any shorter or more efficient way to do lines 6-8 for larger numbers?
Since you are using the prime library, it has a prime_division method:
require 'prime'
13335.prime_division
# => [[3, 1], [5, 1], [7, 1], [127, 1]]
13335.prime_division[0][0]
# => 3
If Prime.prime? is false for 1, it will fail the "if" and keeps going. Try making your array go from 3..sqrt(number)... which will exclude 1, and you've already established the number is odd, so leave out 2 too, and of course there's no need to look at anything higher than the square root either; (because factors always come in pairs a*b=n where a and b are factors; in the case of the square root, a = b... in all other cases, one is less than, and the other greater than, the square root).
Also, rather than gathering the entire collection, consider a regular loop that short circuits the instant it finds a prime factor: why find all factors if all you want is the smallest; (e.g. for 3333, you can quickly find out the smallest prime factor is 3, but would do a lot more steps to find all factors).

Allocate an array of integers proportionally compensating for rounding errors

I have an array of non-negative values. I want to build an array of values who's sum is 20 so that they are proportional to the first array.
This would be an easy problem, except that I want the proportional array to sum to exactly
20, compensating for any rounding error.
For example, the array
input = [400, 400, 0, 0, 100, 50, 50]
would yield
output = [8, 8, 0, 0, 2, 1, 1]
sum(output) = 20
However, most cases are going to have a lot of rounding errors, like
input = [3, 3, 3, 3, 3, 3, 18]
naively yields
output = [1, 1, 1, 1, 1, 1, 10]
sum(output) = 16 (ouch)
Is there a good way to apportion the output array so that it adds up to 20 every time?
There's a very simple answer to this question: I've done it many times. After each assignment into the new array, you reduce the values you're working with as follows:
Call the first array A, and the new, proportional array B (which starts out empty).
Call the sum of A elements T
Call the desired sum S.
For each element of the array (i) do the following:
a. B[i] = round(A[i] / T * S). (rounding to nearest integer, penny or whatever is required)
b. T = T - A[i]
c. S = S - B[i]
That's it! Easy to implement in any programming language or in a spreadsheet.
The solution is optimal in that the resulting array's elements will never be more than 1 away from their ideal, non-rounded values. Let's demonstrate with your example:
T = 36, S = 20. B[1] = round(A[1] / T * S) = 2. (ideally, 1.666....)
T = 33, S = 18. B[2] = round(A[2] / T * S) = 2. (ideally, 1.666....)
T = 30, S = 16. B[3] = round(A[3] / T * S) = 2. (ideally, 1.666....)
T = 27, S = 14. B[4] = round(A[4] / T * S) = 2. (ideally, 1.666....)
T = 24, S = 12. B[5] = round(A[5] / T * S) = 2. (ideally, 1.666....)
T = 21, S = 10. B[6] = round(A[6] / T * S) = 1. (ideally, 1.666....)
T = 18, S = 9. B[7] = round(A[7] / T * S) = 9. (ideally, 10)
Notice that comparing every value in B with it's ideal value in parentheses, the difference is never more than 1.
It's also interesting to note that rearranging the elements in the array can result in different corresponding values in the resulting array. I've found that arranging the elements in ascending order is best, because it results in the smallest average percentage difference between actual and ideal.
Your problem is similar to a proportional representation where you want to share N seats (in your case 20) among parties proportionnaly to the votes they obtain, in your case [3, 3, 3, 3, 3, 3, 18]
There are several methods used in different countries to handle the rounding problem. My code below uses the Hagenbach-Bischoff quota method used in Switzerland, which basically allocates the seats remaining after an integer division by (N+1) to parties which have the highest remainder:
def proportional(nseats,votes):
"""assign n seats proportionaly to votes using Hagenbach-Bischoff quota
:param nseats: int number of seats to assign
:param votes: iterable of int or float weighting each party
:result: list of ints seats allocated to each party
"""
quota=sum(votes)/(1.+nseats) #force float
frac=[vote/quota for vote in votes]
res=[int(f) for f in frac]
n=nseats-sum(res) #number of seats remaining to allocate
if n==0: return res #done
if n<0: return [min(x,nseats) for x in res] # see siamii's comment
#give the remaining seats to the n parties with the largest remainder
remainders=[ai-bi for ai,bi in zip(frac,res)]
limit=sorted(remainders,reverse=True)[n-1]
#n parties with remainter larger than limit get an extra seat
for i,r in enumerate(remainders):
if r>=limit:
res[i]+=1
n-=1 # attempt to handle perfect equality
if n==0: return res #done
raise #should never happen
However this method doesn't always give the same number of seats to parties with perfect equality as in your case:
proportional(20,[3, 3, 3, 3, 3, 3, 18])
[2,2,2,2,1,1,10]
You have set 3 incompatible requirements. An integer-valued array proportional to [1,1,1] cannot be made to sum to exactly 20. You must choose to break one of the "sum to exactly 20", "proportional to input", and "integer values" requirements.
If you choose to break the requirement for integer values, then use floating point or rational numbers. If you choose to break the exact sum requirement, then you've already solved the problem. Choosing to break proportionality is a little trickier. One approach you might take is to figure out how far off your sum is, and then distribute corrections randomly through the output array. For example, if your input is:
[1, 1, 1]
then you could first make it sum as well as possible while still being proportional:
[7, 7, 7]
and since 20 - (7+7+7) = -1, choose one element to decrement at random:
[7, 6, 7]
If the error was 4, you would choose four elements to increment.
A naïve solution that doesn't perform well, but will provide the right result...
Write an iterator that given an array with eight integers (candidate) and the input array, output the index of the element that is farthest away from being proportional to the others (pseudocode):
function next_index(candidate, input)
// Calculate weights
for i in 1 .. 8
w[i] = candidate[i] / input[i]
end for
// find the smallest weight
min = 0
min_index = 0
for i in 1 .. 8
if w[i] < min then
min = w[i]
min_index = i
end if
end for
return min_index
end function
Then just do this
result = [0, 0, 0, 0, 0, 0, 0, 0]
result[next_index(result, input)]++ for 1 .. 20
If there is no optimal solution, it'll skew towards the beginning of the array.
Using the approach above, you can reduce the number of iterations by rounding down (as you did in your example) and then just use the approach above to add what has been left out due to rounding errors:
result = <<approach using rounding down>>
while sum(result) < 20
result[next_index(result, input)]++
So the answers and comments above were helpful... particularly the decreasing sum comment from #Frederik.
The solution I came up with takes advantage of the fact that for an input array v, sum(v_i * 20) is divisible by sum(v). So for each value in v, I mulitply by 20 and divide by the sum. I keep the quotient, and accumulate the remainder. Whenever the accumulator is greater than sum(v), I add one to the value. That way I'm guaranteed that all the remainders get rolled into the results.
Is that legible? Here's the implementation in Python:
def proportion(values, total):
# set up by getting the sum of the values and starting
# with an empty result list and accumulator
sum_values = sum(values)
new_values = []
acc = 0
for v in values:
# for each value, find quotient and remainder
q, r = divmod(v * total, sum_values)
if acc + r < sum_values:
# if the accumlator plus remainder is too small, just add and move on
acc += r
else:
# we've accumulated enough to go over sum(values), so add 1 to result
if acc > r:
# add to previous
new_values[-1] += 1
else:
# add to current
q += 1
acc -= sum_values - r
# save the new value
new_values.append(q)
# accumulator is guaranteed to be zero at the end
print new_values, sum_values, acc
return new_values
(I added an enhancement that if the accumulator > remainder, I increment the previous value instead of the current value)

Resources