Scala - 将两个序列组合成连续增加的三元组

时间:2015-06-22 18:55:29

标签: scala

解决以下问题的有效且有效的方法是什么?在命令式的风格中,这可以在线性时间内完成。

鉴于两个已排序的序列pqf会返回三元组的序列r(或任何集合),其中每个三元组(a,b,c)中的r,以下内容:

  1. a< b< c
  2. 以下两个中的一个:
    • ac是两个连续的元素p,而b位于q
    • ac是两个连续的元素q,而b位于p
  3. 示例: 请考虑以下两个序列。

    val p = Seq(1,4,5,7,8,9)
    val q = Seq(2,3,6,7,8,10)
    

    然后f(p,s)计算以下序列:

    Seq((1,2,4), (1,3,4), (5,6,7), (3,4,6), (3,5,6), (8,9,10))
    

    目前的解决方案:我觉得这个非常优雅。我正在寻找一个更好的。

        def consecutiveTriplesOneWay(s1: Seq[Int], s2:Seq[Int]) = {
            for {
                i <- 0 until s1.size - 1 if s1(i) < s1(i+1)
                j <- 0 until s2.size if s1(i) < s2(j) &&  s2(j) < s1(i+1)
            } yield (s1(i), s2(j), s1(i+1))
        }
    
        def consecutiveTriples(s1: Seq[Int], s2:Seq[Int]) =
            consecutiveTriplesOneWay(s1, s2) ++ consecutiveTriplesOneWay(s2, s1)
    
        def main(args: Array[String]) {
            val p = Seq(1,4,5,7,8,9)
            val q = Seq(2,3,6,7,8,10)
    
            consecutiveTriples(p, q).foreach(println(_))
        }
    

    编辑: 我的必要解决方案

    def consecutiveTriplesOneWayImperative(s1: Seq[Int], s2:Seq[Int]) = {
        var i = 0
        var j = 0
        val triples = mutable.MutableList.empty[(Int,Int,Int)]
        while (i < s1.size - 1 && j < s2.size) {
            if (s1(i) < s2(j) && s2(j) < s1(i + 1)) {
                triples += ((s1(i), s2(j), s1(i + 1)))
                j += 1
            } else if (s1(i) >= s2(j))
                j += 1
            else
                i += 1
        }
        triples.toSeq
    }
    
    def consecutiveTriples(s1: Seq[Int], s2:Seq[Int]) = 
        consecutiveTriplesOneWayImperative(s1,s2) ++ 
                consecutiveTriplesOneWayImperative(s2,s1)
    

1 个答案:

答案 0 :(得分:1)

势在必行的解决方案转化为tailrec。比特冗长,但有效

def consecutiveTriplesRec(s1: Seq[Int], s2: Seq[Int]) = {
  @tailrec
  def consTriplesOneWay(left: Seq[Int], right: Seq[Int],
                        triples: Seq[(Int, Int, Int)]): Seq[(Int, Int, Int)] = {
    (left, right) match {
      case (l1 :: l2 :: ls, r :: rs) =>
        if (l1 < r && r < l2) consTriplesOneWay(left, rs, (l1, r, l2) +: triples)
        else if (l1 >= r) consTriplesOneWay(left, rs, triples)
        else consTriplesOneWay(l2 :: ls, right, triples)
      case _ => triples
    }
  }
  consTriplesOneWay(s1, s2, Nil) ++ consTriplesOneWay(s2, s1, Nil)
}