【问题标题】:Three Sum to N in ScalaScala中的三个和到N
【发布时间】:2015-02-15 22:50:36
【问题描述】:

有没有比这个例子更好的方法来从一个列表中找到三个在scala中总和为零的数字?现在,我觉得我的函数方式可能不是最有效的,它包含重复的元组。在我当前的示例中,消除重复元组的最有效方法是什么?

def secondThreeSum(nums:List[Int], n:Int):List[(Int,Int,Int)] = {
  val sums = nums.combinations(2).map(combo => combo(0) + combo(1) -> (combo(0), combo(1))).toList.toMap

  nums.flatMap { num =>
    val tmp = n - num
    if(sums.contains(tmp) && sums(tmp)._1 != num && sums(tmp)._2 != num) Some((num, sums(tmp)._1, sums(tmp)._2)) else None
  }
}

【问题讨论】:

  • 我认为更有效的策略之一...是 1) 对列表进行排序。 2)添加最大和最小的数字......使用二进制搜索搜索第三个数字(使得 sum == 0)。如果总和为 0,则保存该元组。否则...将这两个二进制搜索数字(总和超过 0)作为第二个数字。使用二分搜索检查。坚持下去……

标签: scala


【解决方案1】:

这很简单,不会重复任何元组:

def f(nums: List[Int], n: Int): List[(Int, Int, Int)] = {
  for {
    (a, i) <- nums.zipWithIndex;
    (b, j) <- nums.zipWithIndex.drop(i + 1)
    c <- nums.drop(j + 1)
    if n == a + b + c
  } yield (a, b, c)
}

【讨论】:

  • 谢谢,我在这里损失了多少运行时效率?这个解是 O(n^3) 吗?
  • 这将返回重复的元组。尝试运行f(List(1,2,3,3), 6)
  • @Marth,取决于您如何定义“重复”,我认为这两者是不同的,因为它们是由列表的不同元素组成的。即使元素值出现多次,代码也不会生成重用相同元素的元组。否则,你知道,.distinct
【解决方案2】:

使用.combinations(3) 生成开始列表中所有不同 可能的三元组,然后只保留总和为n 的那些:

scala> def secondThreeSum(nums:List[Int], n:Int):List[(Int,Int,Int)] = {
         nums.combinations(3)
             .collect { case List(a,b,c) if (a+b+c) == n => (a,b,c) }
             .toList
       }
secondThreeSum: (nums: List[Int], n: Int)List[(Int, Int, Int)]

scala> secondThreeSum(List(1,2,3,-5,2), 0)
res3: List[(Int, Int, Int)] = List((2,3,-5))

scala> secondThreeSum(List(1,2,3,-5,2), -1)
res4: List[(Int, Int, Int)] = List((1,3,-5), (2,2,-5))

【讨论】:

  • 谢谢,我在这里损失了多少运行时效率?这个解是 O(n^3) 吗?
【解决方案3】:

这是一个 O(n^2*log(n)) 的解决方案。因此,对于大型列表,它要快得多。 它还使用较低级别的语言功能来进一步提高速度。

def f(nums: List[Int], n: Int): List[(Int, Int, Int)] = {
  val result = scala.collection.mutable.ArrayBuffer.empty[(Int, Int, Int)]
  val array = nums.toArray
  val mapValueToMaxIndex = scala.collection.mutable.Map.empty[Int, Int]
  nums.zipWithIndex.foreach {
    case (n, i) => mapValueToMaxIndex += (n -> math.max(i, (mapValueToMaxIndex.getOrElse(n, i))))
  }
  val size = array.size
  var i = 0
  while(i < size) {
    val a = array(i)
    var j = i+1
    while(j < size) {
      val b = array(j)
      val c = n - b - a
      mapValueToMaxIndex.get(c).foreach { maxIndex =>
        if(maxIndex > j) result += ((a, b, c))
      }
      j += 1
    }
    i += 1
  }
  result.toList
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 2020-02-06
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 2015-05-01
    相关资源
    最近更新 更多