coin change algorithm in scala using recursion - scala

I am trying to program the coin change problem in Scala using recursion. The code that i have written is as follows.
def countChange(money: Int, coins: List[Int]): Int = {
def ways(change: List[Int], size: Int, capacity: Int): Int = {
if(capacity == 0) 1
if((capacity < 0) || (size <= 0)) 0
//println and readLine to check and control each recursive call.
println("calling ways(",change, change.length-1, capacity,") + ways(",change, change.length, capacity - change(change.length - 1),")")
readLine()
//
ways(change, change.length-1, capacity) + ways(change, change.length, capacity - change(change.length - 1))
}
ways(coins, coins.length, money)
}
On running the code, it does not terminate and keeps on calling the first recursive call. Where am I going wrong?

Nice and simple
def countChange(money: Int, coins: List[Int]): Int = {
if(money == 0)
1
else if(money > 0 && !coins.isEmpty)
countChange(money - coins.head, coins) + countChange(money, coins.tail)
else
0
}

Here is my implementation:
I have tested it and it works fine
def countChange(money: Int, coins: List[Int]): Int = {
def count(capacity: Int, changes: List[Int]): Int = {
if (capacity == 0)
1
else if (capacity < 0)
0
else if (changes.isEmpty && capacity >= 1)
0
else
count(capacity, changes.tail)
+ count(capacity - changes.head, changes)
}
count(money, coins.sortWith(_.compareTo(_) < 0))
}

Just another solution
def countChange(amount: Int, coins: List[Int]): Int = coins match {
case _ if amount == 0 => 1
case h :: t if amount > 0 => countChange(amount - h, h :: t) + countChange(amount, t)
case _ => 0
}

Simply stating a value does not make Scala return it; you either need an explicit return, or it has to be the last item stated. Thus:
if (capacity == 0) return 1
or
if (capacity == 0) 1
else if (...)
else { ... }

Hey I just thought it would be better to see not only the amount but also the list of them, so put on top of the above example like :
def moneyChanges(money: Int, coins: List[Int]) : Option[List[Seq[Int]]]= {
var listOfChange=List[Seq[Int]]()
def changeMoney(capacity: Int, changes: List[Int], listOfCoins: Option[Seq[Int]]): Int = {
if (capacity == 0) {
listOfChange = listOfCoins.get :: listOfChange
1
} else if (capacity < 0)
0
else if (changes.isEmpty && capacity >= 1)
0
else {
changeMoney(capacity, changes.tail, listOfCoins) +
changeMoney(capacity - changes.head, changes,
Some(changes.head +: listOfCoins.getOrElse(Seq())))
}
}
changeMoney(money, coins.sortWith(_.compareTo(_) < 0), None)
Some(listOfChange)
}

here is a DP approach to reduce a lot of re-calculation in recursive approach
object DP {
implicit val possibleCoins = List(1, 5, 10, 25, 100)
import collection.mutable.Map
def countChange(amount: Int)(implicit possibleCoins: List[Int]) = {
val min = Map((1 to amount).map (_->Int.MaxValue): _*)
min(0) = 0
for {
i <- 1 to amount
coin <- possibleCoins
if coin <= i && min(i - coin) + 1 < min(i)
} min(i) = min(i-coin) + 1
min(amount)
}
def main(args: Array[String]) = println(countChange(97))
}
see DP from novice to advanced for algorithm

Below code is similar to one of the above example except I am using match case instead of if else
def countChange(money: Int, coins: List[Int]): Int = {
def change(m: Int, coinList: List[Int], count: Int): Int =
m match {
case _ if m < 0 => count
case _ if coinList.isEmpty => {
m match {
case 0 => count + 1
case _ => count
}
}
case _ => change(m, coinList.tail, count) + change(m - coinList.head, coinList, count)
}
change(money, coins, 0)
}

Here is my code: It's not optimized but works on all test cases.
The idea is to subtract first coin of list from from money until it becomes 0. Once it becomes 0, it will return 1 which means one solution is possible. To add all solutions coming from different recursion I used foldLeft.
(iterating list using foldLeft, so first goes in 1, then again goes in recursion and iterate for (1, 2) list)
[4, (1, 2)].
/(1 as cn) \ (2 as cn)
[3, (1, 2)]. [2, (2)]
/(-1) \(-2) \
[2, (1, 2)]. [1, (2)]. [0, (2)]
/.(-1) \(-2)
[1, (1, 2)]. [0, (2)]
/. (-1) \(-2)
[0, (1, 2)]. [-1, (2)]
def countChange(money: Int, coins: List[Int]): Int = coins.foldLeft(0)((accum, cn) =>
(money, cn) match {
case (money, _) if money < 0 => 0
case (0, _) => 1
case (curr_money, curr_coin) =>
val (before_curr_coin, after_curr_coin) = coins.span(_ != curr_coin)
accum + countChange(curr_money - curr_coin, after_curr_coin)
})

This will handle the case where money is zero but not negative coins...
def countChange(money: Int, coins: List[Int]): Int = {
def loop(money: Int, coins: List[Int]): Int = {
if(money == 0) {
1
} else if(money > 0 && !coins.isEmpty) {
loop(money - coins.head, coins) + loop(money, coins.tail)
} else {
0
}
}
if(money == 0) {
0
} else {
loop(money: Int, coins: List[Int])
}
}

Related

Need help to check scala code can be made concise. Find all factors of n

Below implementation is to find all factors of given 'n' using scala. Can this scala code be concise ? Please note that the below code has O(sqrt(n)).
#scala.annotation.tailrec
def helper(n: Int, current: Int, acc: List[Int]): List[Int] = {
if (current > math.sqrt(n)) acc
else if (n % current == 0) {
val a = n / current
val b = n / a
helper(n, current + 1, acc :+ a :+ b)
} else helper(n, current + 1, acc)
}
helper(A, 1, List.empty[Int]).sorted.toArray
I am not looking for the below solution because this is O(n) solution.
def factors(n: Int): List[Int] = {
(1 to n).filter(n % _ == 0)
}
def factors(n: Int): List[Int] = {
(1 to n).filter(n % _ == 0)
}
Is indeed O(n).
But
def factors(n: Int) =
(1 to sqrt(n).toInt).filter(n % _ == 0).flatMap { k => Seq(k, n/k) }
is O(sqrt(n)) :)

found : Unit required: List[Int] type mismatch error for for loop

type mismatch error found : Unit required: List[Int], for for loop in scal how to resolve ?
i am writing this function and it is giving me error for the first for loop.
def f(num:Int,arr:List[Int]):List[Int] = {
for (i <- arr){
for (j <- 0 until num){
var tmplst = List[Int]()
i :: tmplst
}
}
}
i was expecting that for each element of array the next for loop will run.
Your function need to return List[Int] which is not happening.
Since you are using mutable variable increase the scope of it and return it something like below:
def f(num: Int, arr: List[Int]): List[Int] = {
var tmplst = List[Int]()
for (i <- arr) {
for (j <- 0 until num) {
tmplst = i :: tmplst
}
}
tmplst
}
println(f(5, List(1, 2))) // List(2, 2, 2, 2, 2, 1, 1, 1, 1, 1)
If you want to make it functional,
def fFunctional(num: Int, arr: List[Int]): List[Int] = {
arr.foldLeft(List.empty[Int]) { case (list, i) =>
(0 until num).foldLeft(list) { case (l, j) => i :: l }
}
}
println(fFunctional(5, List(1, 2)))
Rewrite the for comprehension as follows:
def f(num:Int,arr:List[Int]):List[Int] =
for {
i <- arr
j <- 0 until num
} yield i

Increasing counter in for loop

I have a scala code looking like this
object Main {
def countChangeIter(money: Int, coins: List[Int], counter: Int): Int=
if (money == 0) 1
else if (money < 0) 0
else {
for (i <- coins.indices) {
counter = counter + countChangeIter(money - coins(i), coins.drop(i), 0)
}
return counter
}
def countChange(money: Int, coins: List[Int]): Int = countChangeIter(money, coins, 0)
}
The issue is with the counter = counter... statement. How can I implement that the counter changes by the sum of the old counter and whatever countChangeIter returns?
many thanks
c14
You can do something like this :
object Main {
def countChangeIter(money: Int, coins: List[Int], counter: Int): Int=
if (money == 0) 1
else if (money < 0) 0
else {
var myCounter = counter
for (i <- coins.indices) {
myCounter = myCounter + countChangeIter(money - coins(i), coins.drop(i), 0)
}
return myCounter
}
def countChange(money: Int, coins: List[Int]): Int = countChangeIter(money, coins, 0)
}
Bear in mind that if you need to do this in a functional programming setting.. there's probably something wrong with the way the code is structured.

Sum of Integers Using a List

I've been trying to finish this scala code that uses a list to output the summation of all positive integers in the list.. I got it working except for having it only work for positive numbers. but i cant get it to only output the positive numbers. I have 2 versions that ive been trying to get to work, i thought maybe it would be easier wit cases, but i ended up running into the same problem. I've been trying if statements with xs<0 , but those don't work, and i cant get the filter to work with the fold. any suggestions with how to handle this?
def sum(xs: List[Int]): Int = {
xs.filter((x: Int) => x > 0)
xs.foldLeft(0) { _ + _ }
}
def sum2(xs: List[Int]): Int = xs match {
case Nil => 0
case y :: ys => y + sum(ys)
}
xs is an immutable List[Int], which means you are not just modifying the same xs value and returning it.
def sum(xs: List[Int]): Int = {
xs.filter((x: Int) => x > 0) // This is a pure expression and effectively does nothing
xs.foldLeft(0) { _ + _ } // This is the value that is returned, modifying the *original* `xs` parameter
}
What you need to do is chain the functions together, to operate on the same value.
def sum(xs: List[Int]): Int = {
xs.filter((x: Int) => x > 0).foldLeft(0) { _ + _ }
}
The type check isn't necessary here, so it can be shorted:
def sum(xs: List[Int]): Int = xs.filter(_ > 0).foldLeft(0)(_ + _)
There is also a sum method on List that does the same thing as your foldLeft.
def sum(xs: List[Int]): Int = xs.filter(_ > 0).sum
List(1, -2, 3).filter(_ > 0).sum // 4
or in a single pass
List(1, -2, 3).foldLeft(0){(acc, i) => if (i > 0) acc + i else acc } //4
Your 1st version is almost right. Remember that filter method doesn't have side effects, so just try this small change:
def sum(xs: List[Int]): Int = {
xs.filter((x: Int) => x > 0).foldLeft(0) { _ + _ }
}
Or simpler version:
def sum(xs: List[Int]): Int = {
xs.filter(_ > 0).sum
}
i ended up trying this , which i think is right. based on the suggestions
val f = xs.filter((x: Int) => x > 0)
f.foldLeft(0) { _ + _ }

StackOverflowError for coin change in Scala?

I'm writing a recursive function for the Coin (change) problem in Scala.
My implementation breaks with StackOverflowError and I can't figure out why it happens.
Exception in thread "main" java.lang.StackOverflowError
at scala.collection.immutable.$colon$colon.tail(List.scala:358)
at scala.collection.immutable.$colon$colon.tail(List.scala:356)
at recfun.Main$.recurs$1(Main.scala:58) // repeat this line over and over
this is my call:
println(countChange(20, List(1,5,10)))
this is my definition:
def countChange(money: Int, coins: List[Int]): Int = {
def recurs(money: Int, coins: List[Int], combos: Int): Int =
{
if (coins.isEmpty)
combos
else if (money==0)
combos + 1
else
recurs(money,coins.tail,combos+1) + recurs(money-coins.head,coins,combos+1)
}
recurs(money, coins, 0)
}
Edit: I just added the else if statement in the mix:
else if(money<0)
combos
it got rid of the error but my output is 1500 something :( what is wrong with my logic?
The first solution in the accepted answer has a redundant last parameter as noted by Paaro so I wanted to get rid of it. The second solution uses map which I wanted to avoid since it wasn't covered yet in the Week 1 or the Scala course I assume you're taking. Also, the second solution, as rightly noted by the author, would be way slower, unless it uses some memoization. Finally, Paaro's solution seems to have an unnecessary nested function.
So here's what I ended up with:
def countChange(money: Int, coins: List[Int]): Int =
if (money < 0)
0
else if (coins.isEmpty)
if (money == 0) 1 else 0
else
countChange(money, coins.tail) + countChange(money - coins.head, coins)
There is no need for braces here, as you can see.
I wonder if it could be further simplified.
Here is the correct solution based on your codes:
def countChange(money: Int, coins: List[Int]): Int = {
def recurs(m: Int, cs: List[Int], cnt: Int): Int =
if(m < 0) cnt //Not a change, keep cnt
else if(cs.isEmpty) {
if(m == 0) cnt + 1 else cnt // plus cnt if find a change
}
else recurs(m, cs.tail, cnt) + recurs(m-cs.head, cs, cnt)
recurs(money, coins, 0)
}
Anyway, there is a short solution(But not efficient, you can cache the middle result to make it efficient.)
def countChange(m: Int, cs: List[Int]): Int = cs match {
case Nil => if(m == 0) 1 else 0
case c::rs => (0 to m/c) map (k => countChange(m-k*c,rs)) sum
}
One can omit the cnt parameter, which is, in fact, never accumulated. The recurs function always returns either 0 or 1, so the optimized algorithm would be:
def countChange(money: Int, coins: List[Int]): Int = {
def recurs(m: Int, cs: List[Int]): Int =
if(m < 0) 0 //Not a change, return 0
else if(cs.isEmpty) {
if(m == 0) 1 else 0 // 1 if change found, otherwise 0
}
else recurs(m, cs.tail) + recurs(m-cs.head, cs)
if(money>0) recurs(money, coins) else 0
}
The #Eastsun solution is good but it fails when money=0 due to it returns 1 instead of 0, but you can fix it easily:
def countChange(money: Int, coins: List[Int]): Int = {
def recurs(m: Int, cs: List[Int], cnt: Int): Int =
if(m < 0) cnt //Not a change, keep cnt
else if(cs.isEmpty) {
if(m == 0) cnt + 1 else cnt // plus cnt if find a change
}
else recurs(m, cs.tail, cnt) + recurs(m-cs.head, cs, cnt)
if(money>0) recurs(money, coins, 0) else 0
}
here is a DP approach to reduce a lot of re-calculation in recursive approach
object DP {
implicit val possibleCoins = List(1, 5, 10, 25, 100)
import collection.mutable.Map
def countChange(amount: Int)(implicit possibleCoins: List[Int]) = {
val min = Map((1 to amount).map (_->Int.MaxValue): _*)
min(0) = 0
for {
i <- 1 to amount
coin <- possibleCoins
if coin <= i && min(i - coin) + 1 < min(i)
} min(i) = min(i-coin) + 1
min(amount)
}
def main(args: Array[String]) = println(countChange(97))
}
see DP from novice to advanced for algorithm
Idea from https://github.com/pathikrit/scalgos/blob/9e99f73b4241f42cc40a1fd890e72dbeda2df54f/src/main/scala/com/github/pathikrit/scalgos/DynamicProgramming.scala#L44
case class Memo[K,I,O](f: I => O)(implicit i2k:I=>K ) extends (I => O) {
import scala.collection.mutable.{Map => Dict}
val cache = Dict.empty[K, O]
override def apply(x: I) = cache getOrElseUpdate (x, f(x))
}
def coinchange(s: List[Int], t: Int) = {
type DP = Memo[ (Int, Int), (List[Int], Int),Seq[Seq[Int]]]
implicit def encode(key: (List[Int], Int)):(Int,Int) = (key._1.length, key._2)
lazy val f: DP = Memo {
case (Nil, 0) => Seq(Nil)
case (Nil, _) => Nil
case (_, x) if x< 0 => Nil
case (a :: as, x) => f(a::as, x - a).map(_ :+ a) ++ f(as, x)
}
f(s, t)
}