This is a follow-up to my previous question.
Suppose I want to find a pair of integers, which sum to a given number x
, in a given sorted array. The well-known "one pass" solution looks like that:
def pair(a: Array[Int], target: Int): Option[(Int, Int)] = {
var l = 0
var r = a.length - 1
var result: Option[(Int, Int)] = None
while (l < r && result.isEmpty) {
(a(l), a(r)) match {
case (x, y) if x + y == target => result = Some(x, y)
case (x, y) if x + y < target => l = l + 1
case (x, y) if x + y > target => r = r - 1
}
}
result
}
How would you suggest write functionally without any mutable state ?
I guess I can write a recursive version with Stream
(lazy list in Scala)
Could you suggest a non-recursive version ?
This is a one liner
It even works on unsorted lists.
But if you want to take advantage of the sorting, just do a binary search for
(n-x)
for everyx
in the array instead of going through the array.Here's a fairly straightforward version. It creates a
Stream
ofVectors
that removes the first or last element on each iteration. Then we limit the size of the otherwise infiniteStream
(-1 so you can't add a number with itself), thenmap
it into the output format and check for the target condition.There are a lot of gems hidden in the companion objects of Scala's collections, like
Stream.iterate
. I highly recommend checking them out. Knowing about them can greatly simplify a problem like this.Without recursion and without a mutable state it can get pretty ugly. Here's my attempt:
Examples:
The
.reverse
in the beginning plus thefoldLeft
with a return when the result is found makes thisO(2n)
.Here's a version that doesn't use indices (which I try to avoid unless there's an important computation with the value of them):
It's recursive, but doesn't need Stream.
tail
andinit
are O(N) for Array but if we use Lists and reverse ther
collection to avoidinit
andlast
an O(N) version can be doneIf we don't care about one-pass (or efficiency generally :)) it's a one liner
unwrapping that into flatmap/map and then using collectFirst gives us this, which is fairly neat and more optimal (but still not O(n)) - it stops at the first correct pair but does more work than necessary to get there.