scala - 给定一个整数数组,使用 Scala 返回两个数字的索引,使它们相加达到特定目标

标签 scala

我通过解决算法问题来练习 Scala,并在 leetcode 中解决了这个问题:

Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

我想出了以下代码

def twoSum(nums: Array[Int], target: Int): Array[Int] = {
    val map = scala.collection.mutable.Map.empty[Int, Int]
    nums.zipWithIndex.foreach{ case(num, idx) => 
        map.get(idx) match {
            case Some(r) => return Array(r, idx)
            case None => map += (idx -> (target-num))
       }
    }
    Array(-1, -1)
}

看来我以错误的方式向 map 添加值,因为对于每个输入,我都会得到一个 Array(-1,-1) 作为结果。

预期的灵魂。

def twoSum(nums: Array[Int], target: Int): Array[Int] = {
    var map = Map.empty[Int, Int]
    for ((v, i) <- nums.zipWithIndex) {
       map.get(v) match {
           case Some(r) => return Array(r, i)
           case None => map ++= Map((target - v) -> i)
       }
    }
    Array(-1, -1)
}

你能指出我的错误并解释如何正确更新 hashMap 吗?在使用可变 Map 更新元素时​​,我引用了此 post

最佳答案

在第二个解决方案中,您有一个值到索引的映射,这是正确的。但在第一个中,您有相反的情况:从索引到值的映射,这是错误的。因此,您必须反转添加到 Map 中的条目:

def twoSum(nums: Array[Int], target: Int): Array[Int] = {
  val map = scala.collection.mutable.Map.empty[Int, Int]
  nums.zipWithIndex.foreach{ case(num, idx) =>
    map.get(num) match {                     // Changed: retrieving the index of the value 
      case Some(r) => return Array(r, idx)
      case None => map += ((target-num) -> idx)  // Changed: adding (value -> index) pairs
    }
  }
  Array(-1, -1)
}

郑重声明,如果您想避免使用可变性和 return,最简单的方法是一次预先计算 Map,然后执行第二遍查找两个索引:

import scala.collection.immutable.HashMap

def twoSum(nums: Array[Int], target: Int): Array[Int] = {
  val indexByValue = HashMap(nums.zipWithIndex: _*)
  val result = nums.indices.collectFirst(Function.unlift { i =>
    indexByValue.get(target - nums(i)).filter(_ != i).map(Array(i, _))
  })
  result.getOrElse(Array(-1, -1))
}

这仍然比可变版本慢,因为它对 nums 进行了两次传递,并急切地构建整个 Map,而原始的可变代码只进行了一次传递并延迟构建Map。要以函数方式在一次传递中延迟计算 Map,您可以在迭代器或某些延迟集合上使用 scanLeft:

import scala.collection.immutable.HashMap

def twoSum(nums: Array[Int], target: Int): Array[Int] = {
  nums.indices.iterator
    .scanLeft(HashMap.empty[Int, Int]) { (map, i) =>
      map + (nums(i) -> i)
    }
    .zipWithIndex
    .collectFirst(Function.unlift { case (indexByValue, i) =>
      indexByValue.get(target - nums(i)).filter(_ != i).map(Array(i, _))
    })
    .getOrElse(Array(-1, -1))
}

关于scala - 给定一个整数数组,使用 Scala 返回两个数字的索引,使它们相加达到特定目标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61634583/

相关文章:

scala - 聚合如何在 Scala 中工作?

scala - 对于某些项目,REPL 在 sbt 中无法使用控制台命令

postgresql - Slick 与 PostgreSQL Scala SBT Intellij IDEA

scala - case语句中的类型推断失败

scala - 如何定义可以是 Array 或 List 的变量

string - 斯卡拉 : cleanest way to recursively parse files checking for multiple strings

scala - 在任一中指定 Case 对象的类型

scala - 我如何最好地在 Akka Actor 之间分享行为?

scala - Greenplum Spark 连接器 org.postgresql.util.PSQLException : ERROR: error when writing data to gpfdist

scala - Scala中的并发 map /foreach