Во втором решении у вас есть карта значений для индексации, и это правильно. Но в первом случае все наоборот: отображение индекса в значение, что неверно. Поэтому вам нужно отменить записи, которые вы добавляете в 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))
}