Search code examples
scalacollections

How to solve Longest Increasing Subarray in Scala functionally?


We can write an imperative solution for Longest Increasing Subarray like this :

def findLengthOfLCIS(nums: Array[Int]): Int = {
  var len = 0
  var left = 0
  for (i <- nums.indices) {
    if (i > 0 && nums(i) <= nums(i - 1)) left = i
    len = math.max(len, i - left + 1)
  }
  len
}

Now I want to write a functional solution without loops and indices that may return also all increasing subarrays.

def findLengthOfLCIS(nums: Array[Int]): Int = {

  @annotation.tailrec
  def spanIncreasing(xs: List[Int], result: List[Int]): (List[Int], List[Int]) = xs match {
    case x :: tail if result.isEmpty || x > result.head => spanIncreasing(tail, x :: result)
    case _ => (result.reverse, xs)
  }

  @annotation.tailrec
  def dropNotIncreasing(xs: List[Int]): List[Int] = xs match {
    case x :: y :: tail if x >= y => dropNotIncreasing(y :: tail)
    case _ => xs
  }

  def step(pair: (List[Int], List[Int])): (List[Int], List[Int]) = {
    spanIncreasing(pair._1, Nil) match {
      case (increasing, tmp) => dropNotIncreasing(tmp) -> increasing
    }
  }

  def increasingSubarrays(xs: List[Int]): Iterator[List[Int]] = {
    if (xs.isEmpty) Iterator(Nil) else
      Iterator.iterate(xs -> List.empty[Int])(step).drop(1).map(_._2).takeWhile(_.nonEmpty)
  }

  increasingSubarrays(nums.toList).map(_.size).max
}

The solution is working but looks monstrous. I guess using fold or unfold instead of iterate will not simplify the solution significantly ... How would you simplify it ?


Solution

  • Is this fp enough?

    def findLengthOfLCIS(nums: Array[Int]): Int = 
        (nums zip nums.tail).scanLeft(1){ 
            case(r, (p, n)) => if(n > p) r + 1 else 1 
        }.max
    

    Or

    def findLengthOfLCIS(nums: Array[Int]): Int = 
        (nums zip nums.tail).foldLeft((1, 1)){ 
            case((r, m), (p, n)) => if(n > p) (r+1, m.max(r+1)) else (1, m) 
        }._2
    

    BTW: If fp style means tedious, I do not want it at all.

    Note: The above solutions assuming that nums is not empty, just as the problem Longest Increasing Subarray says. But it is easy to make it works for empty array, and keep one line.