Optimization of simple functions containing loops or recursion - scala

I'm working on a problem in codewars and I got my code to work, but it times out. I tried both recursion and loops but both timeout and calculate in similar amounts of time on the simple tests. I don't know how to optimize further either within my novice ability.
Recursion:
def recursive(p: Int, n: Int, l: List[Int], x: List[Int]): List[Int] = {
if (n == p)
x
else
recursive(p, n + 1, l, (l.drop(p - n - 1).sum :: x))
}
def partsSums(l: List[Int]): List[Int] = {
val a = l.length
recursive(a, 0, l, List(0))
}
Loop:
def partsSums(l: List[Int]): List[Int] = {
val g = l.length
var x = List(0)
var n = 0
while (n != g) {
x = (l.drop(g - n - 1).sum) :: x
n += 1
}
x
}

The reason why your two functions time out is both their time complexities are O(n^2). Actually only O(n) is needed. A simple solution as following:
l.scanRight(0)(_ + _)
If you prefer to a solution with tail recursion, this one should work:
def rcumsum(xs: List[Int]): List[Int] = {
def imp(ys: List[Int], cum: List[Int], acc: Int): List[Int] = ys match {
case Nil => cum
case y::rs => imp(rs, (y+acc)::cum, y+acc)
}
imp(xs.reverse, List(0), 0)
}

Related

Swap all Integers of a List with Scala

If I have a swap method, which can swap two Integers in a List:
def swap[E]: (List[E], Int, Int) => List[E] = (ls, i, j) =>
ls.updated(i, ls(j)).updated(j, ls(i))
And now I want to swap all Integers of a list using this method. That means the result should be like this:
swapAll(List(1,2,3)) == List(List(2,1,3), List(3,2,1), List(1,3,2))
I thought of something like this:
def swapAll: List[Int] => List[List[Int]] = ls => for(i <- 0 to ls.length; j <- i to ls.length) yield List(swap(ps, i, j))
But it doesn't work, does somebody have an Idea?
Almost there.
def swap[E](ls: List[E], i: Int, j: Int): List[E] = {
ls.updated(i, ls(j)).updated(j, ls(i))
}
def swapAll(ps: List[Int]): List[List[Int]] = {
val n = ps.size
(for {
i <- 0 until n
j <- (i + 1) until n
} yield swap(ps, i, j))(collection.breakOut)
}
Example:
swapAll(List(1, 2, 3))
// List(List(2, 1, 3), List(3, 2, 1), List(1, 3, 2))
The breakOut is a special explicitly inserted CanBuildFrom. It's necessary because without it, the type of the produced collection is some weird IndexedSequence derived from the 0 until n Range, but you want a List instead.

Scala Recursion Over Multiple Lists

I have this function that takes two lists and returns the sum of the two lists.
Example:
def sumOfSums(a: List[Int], b: List[Int]): Int = {
var sum = 0
for(elem <- a) sum += elem
for(elem <- b) sum += elem
sum
}
Simple enough, however now I'm trying to do it recursively and the second list parameter is throwing me off.
What I have so far:
def sumOfSumsRec(a: List[Int], b: List[Int], acc: Int): Int = a match {
case Nil => acc
case h :: t => sumOfSumsRec(t, acc + h)
}
There's 2 problems here:
I'm only matching on the 'a' List
I'm getting an error when I try to do acc + h, im not sure why.
Question: How can I recursively iterate over two lists to get their sum?
Pattern match both lists:
import scala.annotation.tailrec
def recSum(a: List[Int], b: List[Int]): Int = {
#tailrec
def recSumInternal(a: List[Int], b: List[Int], acc: Int): Int = {
(a, b) match {
case (x :: xs, y :: ys) => recSumInternal(xs, ys, x + y + acc)
case (x :: xs, Nil) => recSumInternal(xs, Nil, x + acc)
case (Nil, y :: ys) => recSumInternal(Nil, ys, y + acc)
case _ => acc
}
}
recSumInternal(a, b, 0)
}
Test:
recSum(List(1,2), List(3,4,5))
Yields:
15
Side note:
For any future readers of this post, I assumed this question was prinarly asked for educational purposes mostly, hence showing how recursion can work on multiple lists, but this is by no mean an idiomatic way to take. For any other purposes, by all means:
scala> val a = List(1,2)
a: List[Int] = List(1, 2)
scala> val b = List(3,4,5)
b: List[Int] = List(3, 4, 5)
scala> a.sum + b.sum
res0: Int = 15
Or consider using mechanisms such as foldLeft, foldMap, etc.

Three Sum to N in Scala

Is there a better way than this example to find three numbers from a list that sum to zero in scala? Right now, I feel like my functional way may not be the most efficient and it contains duplicate tuples. What is the most efficient way to get rid of duplicate tuples in my current example?
def secondThreeSum(nums:List[Int], n:Int):List[(Int,Int,Int)] = {
val sums = nums.combinations(2).map(combo => combo(0) + combo(1) -> (combo(0), combo(1))).toList.toMap
nums.flatMap { num =>
val tmp = n - num
if(sums.contains(tmp) && sums(tmp)._1 != num && sums(tmp)._2 != num) Some((num, sums(tmp)._1, sums(tmp)._2)) else None
}
}
This is pretty simple, and doesn't repeat any tuples:
def f(nums: List[Int], n: Int): List[(Int, Int, Int)] = {
for {
(a, i) <- nums.zipWithIndex;
(b, j) <- nums.zipWithIndex.drop(i + 1)
c <- nums.drop(j + 1)
if n == a + b + c
} yield (a, b, c)
}
Use .combinations(3) to generate all distinct possible triplets of your start list, then keep only those that sum up to n :
scala> def secondThreeSum(nums:List[Int], n:Int):List[(Int,Int,Int)] = {
nums.combinations(3)
.collect { case List(a,b,c) if (a+b+c) == n => (a,b,c) }
.toList
}
secondThreeSum: (nums: List[Int], n: Int)List[(Int, Int, Int)]
scala> secondThreeSum(List(1,2,3,-5,2), 0)
res3: List[(Int, Int, Int)] = List((2,3,-5))
scala> secondThreeSum(List(1,2,3,-5,2), -1)
res4: List[(Int, Int, Int)] = List((1,3,-5), (2,2,-5))
Here is a solution that's O(n^2*log(n)). So it's quite a lot faster for large lists.
Also it uses lower level language features to increase the speed even further.
def f(nums: List[Int], n: Int): List[(Int, Int, Int)] = {
val result = scala.collection.mutable.ArrayBuffer.empty[(Int, Int, Int)]
val array = nums.toArray
val mapValueToMaxIndex = scala.collection.mutable.Map.empty[Int, Int]
nums.zipWithIndex.foreach {
case (n, i) => mapValueToMaxIndex += (n -> math.max(i, (mapValueToMaxIndex.getOrElse(n, i))))
}
val size = array.size
var i = 0
while(i < size) {
val a = array(i)
var j = i+1
while(j < size) {
val b = array(j)
val c = n - b - a
mapValueToMaxIndex.get(c).foreach { maxIndex =>
if(maxIndex > j) result += ((a, b, c))
}
j += 1
}
i += 1
}
result.toList
}

Scala find an Int between a List of Int

I have an Int and I need to find in a List of Ints the upper and lower bounds for this Int.
For example:
In a List(1,3,6,9), when I ask for 2, I should get 1 and 3. Is there any pre-built function in the Scala collection API that I can use? I know that I can achieve this using the filter function, but I'm looking for an already existing API if any?
So, not built in, but here you go. Since you want return nothing for (e.g.) 0 and 10, we need to return an option.
var rs = List(1, 3, 6, 9) //> rs : List[Int] = List(1, 3, 6, 9)
def bracket(n: Int, rs: List[Int]) = {
val (l, r) = rs.span(_ < n)
if (l == Nil || r == Nil)
None
else if (r.head == n)
Some((n, n))
else
Some((l.last, r.head))
}
bracket(0, rs) //> res0: Option[(Int, Int)] = None
bracket(2, rs) //> res1: Option[(Int, Int)] = Some((1,3))
bracket(6, rs) //> res2: Option[(Int, Int)] = Some((6,6))
bracket(10, rs) //> res3: Option[(Int, Int)] = None
Alternative if you know the edge cases can't happen:
def bracket(n: Int, rs: List[Int]) = {
val (l, r) = rs.span(_ < n)
if (r.head == n)
(n, n)
else
(l.last, r.head)
}
bracket(2, rs) //> res0: (Int, Int) = (1,3)
bracket(6, rs) //> res1: (Int, Int) = (6,6)
(will throw an exception if there is no lower and upper bound for n)
If you can't have edge cases and you are OK with a tuple that is (<=, >) then simply
def bracket(n: Int, rs: List[Int]) = {
val (l, r) = rs.span(_ <= n)
(l.last, r.head)
}
bracket(2, rs) //> res0: (Int, Int) = (1,3)
bracket(6, rs) //> res1: (Int, Int) = (6,9)
You can use grouped or slide iterators to take 2 elements at a time and test condition:
// you can also add 'numbers.sorted' if your list is not sorted
def findBoundries(x: Int, numbers: List[Int]): Option[List[Int]] =
numbers.grouped(2).find {
case a :: b :: Nil => a <= x && x <= b
}
findBoundries(2,List(1,3,6,9))
You can, as a workaround, also convert your List to a NavigableSet (Java class that has higher and lower methods, which do more or less what you require).

Convert iterative two sum k to functional

I have this code in Python that finds all pairs of numbers in an array that sum to k:
def two_sum_k(array, k):
seen = set()
out = set()
for v in array:
if k - v in seen:
out.add((min(v, k-v), max(v, k-v)))
seen.add(v)
return out
Can anyone help me convert this to Scala (in a functional style)? Also with linear complexity.
I think this is a classic case of when a for-comprehension can provide additional clarity
scala> def algo(xs: IndexedSeq[Int], target: Int) =
| for {
| i <- 0 until xs.length
| j <- (i + 1) until xs.length if xs(i) + xs(j) == target
| }
| yield xs(i) -> xs(j)
algo: (xs: IndexedSeq[Int], target: Int)scala.collection.immutable.IndexedSeq[(Int, Int)]
Using it:
scala> algo(1 to 20, 15)
res0: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,14), (2,13), (3,12), (4,11), (5,10), (6,9), (7,8))
I think it also doesn't suffer from the problems that your algorithm has
I'm not sure this is the clearest, but folds usually do the trick:
def two_sum_k(xs: Seq[Int], k: Int) = {
xs.foldLeft((Set[Int](),Set[(Int,Int)]())){ case ((seen,out),v) =>
(seen+v, if (seen contains k-v) out+((v min k-v, v max k-v)) else out)
}._2
}
You could just filter for (k-x <= x) by only using those x as first element, which aren't bigger than k/2:
def two_sum_k (xs: List[Int], k: Int): List [(Int, Int)] =
xs.filter (x => (x <= k/2)).
filter (x => (xs contains k-x) && (xs.indexOf (x) != xs.lastIndexOf (x))).
map (x => (x, k-x)).distinct
My first filter on line 3 was just filter (x => xs contains k-x)., which failed as found in the comment by Someone Else. Now it's more complicated and doesn't find (4, 4).
scala> li
res6: List[Int] = List(2, 3, 3, 4, 5, 5)
scala> two_sum_k (li, 8)
res7: List[(Int, Int)] = List((3,5))
def twoSumK(xs: List[Int], k: Int): List[(Int, Int)] = {
val tuples = xs.iterator map { x => (x, k-x) }
val potentialValues = tuples map { case (a, b) => (a min b) -> (a max b) }
val values = potentialValues filter { xs contains _._2 }
values.toSet.toList
}
Well, a direct translation would be this:
import scala.collection.mutable
def twoSumK[T : Numeric](array: Array[T], k: T) = {
val num = implicitly[Numeric[T]]
import num._
val seen = mutable.HashSet[T]()
val out: mutable.Set[(T, T)] = mutable.HashSet[(T, T)]()
for (v <- array) {
if (seen contains k - v) out += min(v, k - v) -> max(v, k - v)
seen += v
}
out
}
One clever way of doing it would be this:
def twoSumK[T : Numeric](array: Array[T], k: T) = {
val num = implicitly[Numeric[T]]
import num._
// One can write all the rest as a one-liner
val s1 = array.toSet
val s2 = s1 map (k -)
val s3 = s1 intersect s2
s3 map (v => min(v, k - v) -> max(v, k - v))
}
This does the trick:
def two_sum_k(xs: List[Int], k: Int): List[(Int, Int)] ={
xs.map(a=>xs.map(b=>(b,a+b)).filter(_._2 == k).map(b=>(b._1,a))).flatten.collect{case (a,b)=>if(a>b){(b,a)}else{(a,b)}}.distinct
}