我尝试在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)
我可以提供一些关于如何改进它以及整个实现的建议或演示代码
答案 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作为示例):
答案 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)
}