Algorithm fails for coin change - algorithm

I am trying to build my last piece of homework from the scala course from coursera however my algorithm seems to fail. I cannot understand however why it fails and why it returns 0.
NOTE I am not asking for a solution to this problem. I want an explanation regarding what is happening with the code and why it fails.
def countChange(money: Int, coins: List[Int]): Int = {
def cc(amount: Int, list: List[Int]): Int = {
println(amount, list);
if (amount == 0) 1
if (amount < 0 || list.isEmpty) 0
else cc(amount - list.head, list) + cc(amount, list.tail)
}
cc(money, coins)
}
The logic was that the number of ways that you can give change to a given amount is equal to the number of ways you can give change using the first type of coin + the number of ways that you can give change to the next type of coin. This resulted in a recursive function which counted all the ways. This was my logic and this was what I tried to build however this is what it returns:
(10,List(2, 3, 5))
(8,List(2, 3, 5))
(6,List(2, 3, 5))
(4,List(2, 3, 5))
(2,List(2, 3, 5))
(0,List(2, 3, 5))
(-2,List(2, 3, 5))
(0,List(3, 5))
(-3,List(3, 5))
(0,List(5))
(-5,List(5))
(0,List())
(2,List(3, 5))
(-1,List(3, 5))
(2,List(5))
(-3,List(5))
(2,List())
(4,List(3, 5))
(1,List(3, 5))
(-2,List(3, 5))
(1,List(5))
(-4,List(5))
(1,List())
(4,List(5))
(-1,List(5))
(4,List())
(6,List(3, 5))
(3,List(3, 5))
(0,List(3, 5))
(-3,List(3, 5))
(0,List(5))
(-5,List(5))
(0,List())
(3,List(5))
(-2,List(5))
(3,List())
(6,List(5))
(1,List(5))
(-4,List(5))
(1,List())
(6,List())
(8,List(3, 5))
(5,List(3, 5))
(2,List(3, 5))
(-1,List(3, 5))
(2,List(5))
(-3,List(5))
(2,List())
(5,List(5))
(0,List(5))
(-5,List(5))
(0,List())
(5,List())
(8,List(5))
(3,List(5))
(-2,List(5))
(3,List())
(8,List())
(10,List(3, 5))
(7,List(3, 5))
(4,List(3, 5))
(1,List(3, 5))
(-2,List(3, 5))
(1,List(5))
(-4,List(5))
(1,List())
(4,List(5))
(-1,List(5))
(4,List())
(7,List(5))
(2,List(5))
(-3,List(5))
(2,List())
(7,List())
(10,List(5))
(5,List(5))
(0,List(5))
(-5,List(5))
(0,List())
(5,List())
(10,List())
0
As you can see it returns 0 even though the steps that it takes as it can be seen from the printed calls seem to be exactly what my logic tried to achieve.
This is the call of the function in the main function:
println ("" + countChange(10,List(2,3,5)))
Please Do not give me baked code which I can copy and paste. I want to know what is wrong with my logic.

You are missing an else:
if (amount == 0) 1 // This value is thrown away
if (amount < 0 || list.isEmpty) 0
else cc(amount - list.head, list) + cc(amount, list.tail)
Just add it before the second if and you'll be okay.
(In case it isn't clear, only the result from the last if/else is returned, so in
if (a) 1
if (b) 2
if (c) 3
else 4
only the last two lines will matter. If you want to choose one of those options,
if (a) 1
else if (b) 2
else if (c) 3
else 4
is what you need.)

Your bug is in the recursive portion of the code:
cc(amount -list.head, list) + cc(amount, list.tail)
If you look at the first part, you're passing the entire list again without removing the head. What that means is that the only way you'll ever get an answer is if the amount is exactly divisible by the coin at the head position of the current list.

Related

Dynamic programming - Tree recursion with Memoization

For the problem:
Consider an insect in an M by N grid. The insect starts at the bottom left corner, (0, 0), and wants to end up at the top right corner, (M-1, N-1). The insect is only capable of moving right or up. Write a function paths that takes a grid length and width and returns the number of different paths the insect can take from the start to the goal.
For example, the 2 by 2 grid has a total of two ways for the insect to move from the start to the goal. For the 3 by 3 grid, the insect has 6 diferent paths (only 3 are shown above).
Below is the recursive solution:
package main
import "fmt"
func paths(m, n int) int {
var traverse func(int, int) int
traverse = func(x, y int) int {
if x >= m || y >= n {
return 0
}
if x == m-1 && y == n-1 {
return 1
}
return traverse(x+1, y) + traverse(x, y+1)
}
return traverse(0, 0)
}
func main() {
fmt.Println(paths(1, 157))
}
As N increases, below is the effect:
fmt.Println(paths(1, 1)) // 1
fmt.Println(paths(2, 2)) // 2
fmt.Println(paths(3, 3)) // 6
fmt.Println(paths(4, 4)) // 20
fmt.Println(paths(5, 5)) // 70
fmt.Println(paths(6, 6)) // 252
fmt.Println(paths(7, 7)) // 924
Memoization can be applied in fibonacci problem, to reuse previous computations, using tree recursion
Does it make sense to memoiz this path problem? to reuse previous computations
(Note: this problem is meant to apply the idea of tree recursion, as mentioned here.)
The problem is well known, and has a solution of (M+N-2 choose M-1) or equivalently (M+N-2 choose N-1). Does it make sense to use memoization which would take O(NM) time? Not really, since binomial coeffecients can be computed in O(min(M,N)) time (arithmetic operations) with relatively simple code.
For example (playground link):
package main
import (
"fmt"
"math/big"
)
func paths(n, m int) *big.Int {
return big.NewInt(0).Binomial(int64(n+m-2), int64(m-1))
}
func main() {
for i := 1; i < 10; i++ {
fmt.Println(i, paths(i, i))
}
}
Yes, it's possible to use memoization. A key observation to make is consider a grid (1, 1) in a 3x3 grid:
(2, 0) (2, 1) (2, 2)
(1, 0) (1, 1) (1, 2)
(0, 0) (0, 1) (0, 2)
The number of paths in grid (1, 1) is equal to the number of paths from (1, 0) plus the number of paths from (0, 1) since there are only two possible ways one can arrive at path (1, 1).
Generalizing:
npath(x, y) = npath(x-1, y) + npath(x, y-1)
where npath(x, y) = the number of possible paths to visit grid (x, y)
Thus, if you build your recursion backwards you can apply memoization. By backwards I mean you have to start from the smaller case where npath(_, 0) = 1 and npath(0, _) = 1. underscore means any value.
A simple run of this algorithm leads to these number of paths in a 3x3 grid:
1 3 6
1 2 3
1 1 1
In fact, you can just do a double nested loop instead of a recursion as an optimization.

What is the origin of Ruby's block syntax?

Ruby has an interesting syntax for blocks (arguments between pipes followed by a sequence of statements):
[1, 2, 3].each do |x|
puts x
end
Rust uses a similar syntax as well:
arr.sort_by_key(|a| {
let intermediate_value = some_function(a);
intermediate_value + 10
});
I'm wondering if this syntax predates Ruby (particularly putting arguments between pipes, which I believe I've seen elsewhere but am not sure where), and if so, what languages use it?
I believe that Smalltalk also uses pipes, but for object initialization, and I can't find any other examples on Google.
Thanks!
Ruby's creator, "Matz", has said Ruby's design was inspired by Perl, Smalltalk, Eiffel, Ada, and Lisp.
From this list, I would say it's most likely from Smalltalk, Eiffel, and Lisp. Examples:
Smalltalk
#(1 2 3 4 5) inject: 0 into: [:sum :number | sum + number]
#(1 2 3 4 5) fold: [:product :number | product * number]
Lisp
(let ((data #(1 2 3 4 5))) ; the array
(values (reduce #'+ data) ; sum
(reduce #'* data))) ; product
(loop for i in '(1 2 3 4 5) sum i)
Eiffel
class
APPLICATION
create
make
feature {NONE}
make
local
test: ARRAY [INTEGER]
do
create test.make_empty
test := <<5, 1, 9, 7>>
io.put_string ("Sum: " + sum (test).out)
io.new_line
io.put_string ("Product: " + product (test).out)
end
sum (ar: ARRAY [INTEGER]): INTEGER
-- Sum of the items of the array 'ar'.
do
across
ar.lower |..| ar.upper as c
loop
Result := Result + ar [c.item]
end
end
product (ar: ARRAY [INTEGER]): INTEGER
-- Product of the items of the array 'ar'.
do
Result := 1
across
ar.lower |..| ar.upper as c
loop
Result := Result * ar [c.item]
end
end
end

Digits after decimal points in printing outputs

I need to do the following computations.
sqrt(abs(pow(a, 2) - pow(b, 2)))
sqrt(abs(pow(a, 2) + pow(b, 2)))
Let a = 4 and b = 5 so the outputs are 3 and 6.40312. Now if I want to print like 3.0 and other one kept as same 6.40312 how can I do that? If I use setprecision() and fixed the outputs are 3.0000and 6.40312. How can I have varible lenght decimal points results with cout?

Scala Performant Filter Subsets in same lists

I am filtering a Set, based on the other values of the same Set, more exactly, filter out the sets that are fully included in another set
Set(Set(1, 2), Set(1, 3), Set(1, 4), Set(1, 2, 3))
This would result in :
Set(Set(1, 4), Set(1, 2, 3))
1,2 and 2,3 being fully included in the last set (Basically, I want only the biggest subsets of the lot)
I have come up with this bit of code, which does the trick :
def filterIncluded(data: Set[Set[Int]]): Set[Set[Int]] = {
data.filterNot{ s =>
data.exists(x => x.size > s.size && s.forall(x.contains))
}
}
It works great, except for one problem : It is extremely inefficient, my actual dataset will have millions of sets which can each have 2 to 100 values in each
Is there any way to make this go faster? (Using another type of collection, different method calls, changing the way it loops, etc.)
In general you can't do better than N^2 because you are searching for collisions in a much bigger space that isn't constrained in any sort of regular way.
But you probably are not solving the problem in general. There's probably a particular structure to your data.
For instance, if the numbers are approximately random, you can count the number of occurrences of each number; if a number appears only once, the set which contains it must not be a strict subset. If you have only a small number, just brute force the search as you did above, and you'll know which are unique. If you start getting a large number of sets with that distinguishing number (not likely if the numbers are approximately random, but let's say you do), you can subdivide again based on a second number. Using your example:
data.toList.flatMap(_.toList).groupBy(identity).map{
case (k,vs) => k -> vs.length
}
// Gives counts: 1 -> 4, 2 -> 2, 3 -> 2, 4 -> 1
// Pick out the set with a 4: it is unique
// Pick out sets with a 2: Set(1, 2), Set(1, 2, 3)
// Run your algorithm to discard Set(1,2)
// Pick out sets with a 3: Set(1, 3), Set(1, 2, 3)
// Run your algorithm to discard Set(1,3)
// Pick out sets with a 1: only Set(1, 2, 3) remains, keep it
Alternatively, if you could have any Int but in practice tend to have a bunch of similar numbers, you can build the set equivalent of a suffix tree. Start with a set which is the union of all your numbers. Then for each element, list every set which has that element. Then, under that list, break it down again by a second element. Any time you get to a level where you actually have the full set, and the list is nonempty, you can discard the full set.
1 -> Set(1, 2, 3), Set(1, 2), Set(1, 3), Set(1, 4)
2 -> Set(1, 2, 3), Set(1, 2)
But we're _at_ 1,2 so
throw away Set(1, 2)
only Set(1, 2, 3) is left--keep it
3 -> Set(1, 2, 3); Set(1, 3)
We're at 1,3 so
throw away Set(1, 3)
the other set is already kept
4 -> Set(1, 4)
Oh, there's only one. Keep it.
The first improvement I can think of would be:
def filterIncluded(data: Set[Set[Int]]): Set[Set[Int]] = {
val undecided = data.toList.sortBy(_.size).reverse
undecided.foldLeft(List.empty[Set[Int]]){ case (goodSets, s) =>
if(goodSets.forall(goodSet => !s.forall(goodSet contains _))) s :: goodSets
else goodSets
}.toSet
}
Sorting is NLogN, but then you only have to compare each element to ones that are already proven good since you can only be a proper subset of a set that is larger or the same size. It's still N^2 but slightly more efficient that your original I think.
Alternatively you could do this more complicated thing which actually sounds like that other fellow's answer where you maintain a map of element to good sets which include it. Then when checking a new set you can just get the sets which include the first element and then for each subsequent element you get which sets have that one and take the intersection until either you have an empty intersection (nothing is a superset) or you run out of elements (everything left is a superset). Here is a possibly ugly implementation:
def filterIncluded(data: Set[Set[Int]]): Set[Set[Int]] = {
def isGood(s: Set[Int], goodSets: Map[Int, Set[Set[Int]]]): Boolean = goodSets.get(s.head) match {
case None => true
case Some(sets) => _isGood(s.tail, sets, goodSets)
}
def _isGood(s: Set[Int], potentialSupersets: Set[Set[Int]], goodSets: Map[Int, Set[Set[Int]]]): Boolean = {
// println(s"s($s)\npotentialSupersets($potentialSupersets)\ngoodSets($goodSets)\n")
goodSets.get(s.head) match {
case None => true
case Some(sets) =>
(s.tail.isEmpty, potentialSupersets & sets) match {
case (true, remaining) if remaining.nonEmpty => false
case (false, remaining) if remaining.nonEmpty => _isGood(s.tail, remaining, goodSets)
case _ => true
}
}
}
def addToGoodSets(s: Set[Int], goodSets: Map[Int, Set[Set[Int]]]): Map[Int, Set[Set[Int]]] = {
s.foldLeft(goodSets){case (g, i) => g + (i -> (g.getOrElse(i, Set.empty)+s))}
}
val undecided = data.toList.sortBy(_.size).reverse
// println("UNDECIDED: "+undecided)
undecided.foldLeft(Map.empty[Int, Set[Set[Int]]]){ case (goodSets, s) =>
if(isGood(s, goodSets)) addToGoodSets( s, goodSets)
else goodSets
}.values.flatten.toSet
}
I honestly am having a bit of a problem analyzing when this is better than anything else, but there you go. Can you tell I'm bored?

Modifying the range of a uniform random number generator

I am given a function rand5() that generates, with a uniform distribution, a random integer in the closed interval [1,5]. How can I use rand5(), and nothing else, to create a function rand7(), which generates integers in [1,7] (again, uniformly distributed) ?
I searched stackoverflow, and found many similar questions, but not exactly like this one.
My initial attempt was rand5() + 0.5*rand5() + 0.5*rand5(). But this won't generate integers from 1 to 7 with uniform probability. Any answers, or links to answers, are very welcome.
Note that a prefect uniform distribution cannot be achieved with a bounded number of draw5() invocations, because for every k: 5^k % 7 != 0 - so you will always have some "spare" elements.
Here is a solution with unbounded number of draw5() uses:
Draw two numbers, x1,x2. There are 5*5=25 possible outcomes for this.
Note that 25/7 ~= 3.57. Chose 3*7=21 combinations, such that each combination will be mapped to one number in [1,7], for all other 4 numbers - redraw.
For example:
(1,1),(1,2),(2,1) : 1
(3,1),(1,3),(3,2): 2
(3,3),(1,4),(4,1): 3
(2,4),(4,2)(3,4): 4
(4,3), (4,4), (1,5): 5
(5,1), (2,5), (5,2) : 6
(5,3), (3,5), (4,5) : 7
(5,4),(5,5),(2,3), (2,2) : redraw
Here's a simple way:
Use rand5() to generate a sequence of three random integers from the set { 1, 2, 4, 5 } (i.e., throw away any 3 that is generated).
If all three numbers are in the set { 1, 2 }, discard the sequence and return to step 1.
For each number in the sequence, map { 1, 2} to 0 and { 4, 5 } to 1. Use these as the three bit values for a 3-bit number. Because the bits cannot all be 0, the number will be in the range [1, 7]. Because each bit is 0 or 1 with equal probability, the distribution over [1, 7] should be uniform.
ok I had to think about it for a while but it is actually not that hard. Imagine instead of rand5 you had rand2 which either outputs 0 or 1. You can make rand2 our of rand5 by simply doing
rand2() {
if(rand5() > 2.5) return 1
else return 0
}
now using rand2 multiple times do a tree to get rand7. For example if you start rand7 can be in [1,2,3,4,5,6,7] after a throw of rand2 which gives 0 you now subset to [1,2,3,4] and after another throw or rand2 which is 1 you subset to [3,4] and a final throw of 1 gives the output of rand7 to be 4. In general this tree trick can work to take a rand2 and map to randx where x is any integer.
Here's one meta-trick which comes in handy for lots of these problems: the bias is introduced when we treat the terms differently in some fashion, so if we treat them all the same at each step and perform operations only on the set, we'll stay out of trouble.
We have to call rand5() at least once (obviously!), but if we branch on that bad things happen unless we're clever. So instead let's call it once for each of the 7 possibilities:
In [126]: import random
In [127]: def r5():
.....: return random.randint(1, 5)
.....:
In [128]: [r5() for i in range(7)]
Out[128]: [3, 1, 3, 4, 1, 1, 2]
Clearly each of these terms was equally likely to be any of these numbers.. but only one of them happened to be 2, so if our rule had been "choose whichever term rand5() returns 2 for" then it would have worked. Or 4, or whatever, and if we simply looped long enough that would happen. So there are lots of way to come up with something that works. Here (in pseudocode -- this is terrible Python) is one way:
import random, collections
def r5():
return random.randint(1, 5)
def r7():
left = range(1, 8)
while True:
if len(left) == 1:
return left[0]
rs = [r5() for n in left]
m = max(rs)
how_many_at_max = rs.count(m)
if how_many_at_max == len(rs):
# all the same: try again
continue
elif how_many_at_max == 1:
# hooray!
return left[rs.index(m)]
# keep only the non-maximals
left = [l for l,r in zip(left, rs) if r != m]
which gives
In [189]: collections.Counter(r7() for _ in xrange(10**6))
Out[189]: Counter({7: 143570, 5: 143206, 4: 142827, 2: 142673, 6: 142604, 1: 142573, 3: 142547})

Resources