2和算法

时间:2017-03-21 02:20:40

标签: scala functional-programming

我尝试在leetcode(https://leetcode.com/problems/two-sum/#/description

中计算出算法的功能实现

我想我需要的是3个函数,如下所示:

  • List[Int] => List[(Int, Int)]压缩位置
  • 的元素
  • List[(Int, Int)], Int, Int => List[((Int, Int) , (Int, Int))]使用元素和位置的其余部分压缩元素和位置,并使用Sum
  • 进行过滤
  • List[((Int, Int) , (Int, Int))] => List[(Int, Int)]映射到位置

代码如下所示:

  def findTwoSumElements(xs: List[Int], sum: Int): List[(Int, Int)] = {
    val zipWithIndex = xs.zipWithIndex
    var tailElements = zipWithIndex

    val result = zipWithIndex.map(t => {
      val element = zipAndFilter(tailElements, t, sum)
      tailElements = tailElements.tail
      element
     }
    )

    result.flatten.map(t => (t._1._2, t._2._2))
  }

  private def zipAndFilter(xs: List[(Int, Int)], x: (Int, Int), sum: Int): List[((Int, Int), (Int, Int))] = {
    xs.map(t => (t, x)).filter(t => (t._1._1 + t._2._1) == sum)
  }

 println(findTwoSumElements(List(1,2,3,4), 10)) //List()
 println(findTwoSumElements(List(1,2,3,4), 7)) //List((3,2))
 println(findTwoSumElements(List(1,2,3,4), 5)) //List((3,0), (2,1))
 println(findTwoSumElements(List(), 5)) //List()

我想通过不使用var

来改进这部分代码
  var tailElements = zipWithIndex

  val result = zipWithIndex.map(t => {
     val element = zipAndFilter(tailElements, t, sum)
     tailElements = tailElements.tail
     element
   }
  )

原因是我想删除重复的Tuple [Int,Int],例如,如果我不改变尾部,它将返回(x,y)和(y,x)

我可以提供一些关于如何改进它以及整个实现的建议或演示代码

5 个答案:

答案 0 :(得分:4)

对于简化的问题,对于每个输入只有一个解决方案,那么您可以将解决方案编写为单行:

def twoSum(nums: List[Int], target: Int): List[Int] =
  nums.combinations(2).find(_.sum == target).get.map(nums.indexOf)

扩展解决方案,具有显式类型:

def twoSum(nums: List[Int], target: Int): List[Int] = {
  val comb: Iterator[List[Int]] = nums.combinations(2) // Get 2-sized combinations iterator
  val find: Option[List[Int]] = comb.find(_.sum == target) // Find the first (and only) combination having sum equals to our target
  val res: List[Int] = find.get // Exactly one solution
  val idx: List[Int] = res.map(nums.indexOf) // Get the indexes in the original list
}

一种替代的通用解决方案,允许多个或根本没有结果(返回List[List[Int]]):

 def twoSum(nums: List[Int], target: Int): List[List[Int]] =
   nums.combinations(2).collect {
     case couple if couple.sum == target =>
       couple.map(nums.indexOf)
   }.toList

可以推广甚至更多接受组合大小(在我们的示例中为2)作为参数

答案 1 :(得分:2)

好的,我会拍摄一下:)

下面的解决方案如何:

  def twoSum(nums: Seq[Int], target: Int): Seq[Int] =
    nums.zipWithIndex.
      filter(x =>
        (nums.take(nums.indexOf(x._1)) ++ nums.drop(nums.indexOf(x._1)+1))
        .contains(target - x._1)).map(_._2)

以下是完成的操作(使用数组[2,7,11,15]和target = 9作为示例):

  1. 我们zip with index让每个号码与其位置配对,例如(2,0),(7,1)...
  2. 我们通过与原始集合中目标(即目标 - 数字)的数量差异来删除每一对,并删除其自身(参见nums。take ++ nums。drop
  3. 我们将每个结果对映射到其位置部分(例如(2,0)=> 0,(7,1)=> 1)
  4. 结果序列仅包含具有添加到目标的相应和对的数字的位置:(0,1)。

答案 2 :(得分:1)

Scala有一个内置的combinations方法,可以为您完成大量工作。这使得查找目标总和变得如此简单:

val result = nums.combinations(2).filter{case List(x, y) => x + y == target}.next

然后您可以通过以下方式将答案映射回索引:

val indices = result map (nums.zipWithIndex.toMap)

答案 3 :(得分:0)

combinations(2)总是会给您O(n ^ 2)的复杂度。 Leetcode将使您的解决方案在输入大量内容时超时。

最后一个.map(nums.indexOf)将不起作用,因为您会错误地回答“ [3,3]寻找6”。

我建议的一种解决方案是

def twoSum(nums: Array[Int], target: Int): Array[Int] = {
    import scala.collection.immutable.HashMap 
    def run(index: Int, map: HashMap[Int, Int]): Array[Int] = {
        val value = nums(index)
        map get (target - value) match {
            case Some(foundInd) => Array(foundInd, index)
            case None => run(index + 1, map + (value -> index))
        }
    }
    run(0, HashMap())
}

它并不是真的很花哨,但它可以线性运行,适用于所有测试用例,并且没有突变。

答案 4 :(得分:0)

 def sol(inputArray: Array[Int], target: Int): Array[Int] = {

    def recPass(list: List[(Int, Int)], map: Map[Int, Int]): Array[Int] = list match {
      case (elem, index) :: tail =>
        val complement = target - elem
        if (map.contains(complement)) Array(map(complement), index)
        else recPass(tail, map + (elem -> index))
      case _ => throw new IllegalArgumentException("No two sum solution")
    }
    recPass(inputArray.zipWithIndex.toList, Map.empty)
  }

  def sol(nums: Array[Int], target: Int): Array[Int] = {
      def tailRec(map: Map[Int, Int], index: Int): Array[Int] = {

  if (index >= nums.length) throw new IllegalArgumentException("No two sum solution") else {
    if (map.contains(nums(index))) {
      Array(map(nums(index)), index)
    } else {
      tailRec(map + (target - nums(index) -> index), index + 1)
    }
  }
}
  tailRec(Map(), 0)
  }