Я решаю задачу «Лучшее время для покупки и продажи акций» на leetcode https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/ с 2 подходами:
Сначала я преобразовал Array в List и рекурсивно обрабатываю список:
def maxProfit(prices: Array[Int]): Int = {
@tailrec
def maxProfitHelp(prices: List[Int], maxProfit: Int, lastBuy: Int): Int = {
prices match {
case Nil => maxProfit
case head :: tail => if (head > lastBuy) {
maxProfitHelp(tail, Math.max(maxProfit, head - lastBuy), lastBuy)
} else {
maxProfitHelp(tail, maxProfit, head)
}
}
}
val listPrices = prices.toList
maxProfitHelp(listPrices.tail, 0, listPrices.head)
}
Это дало время производительности 962 мс. (Память: 71,70 МБ)
Во-вторых, я попытался обработать исходный массив тем же рекурсивным способом.
def maxProfitWithoutList(prices: Array[Int]): Int = {
@tailrec
def maxProfitHelp(prices: Array[Int], maxProfit: Int, lastBuy: Int): Int = {
prices match {
case c if c.isEmpty => maxProfit
case c => if (c.head > lastBuy) {
maxProfitHelp(c.tail, Math.max(maxProfit, c.head - lastBuy), lastBuy)
} else {
maxProfitHelp(c.tail, maxProfit, c.head)
}
}
}
maxProfitHelp(prices.tail, 0, prices.head)
}
А время выполнения составляет 9134 мс. (Память: 75,47 МБ)
Таким образом, сложность рекурсии Array в 10 раз хуже (!), чем рекурсии List!
Почему это случилось?
Потому что взятие хвоста Array
копирует всю память. Не используйте Arrays
как новичок, у них много проблем, одна из них ужасна в производительности, если вы не используете их должным образом.
Раньше при использовании leetcode я довольно часто сталкивался с тем, что даже один и тот же код имел совершенно разное время выполнения (хотя и не в 10 раз), поэтому попробуйте отправить одно и то же решение несколько раз или лучше использовать соответствующие инструменты для сравнительного анализа.
Насколько я вижу, Array.tail
возвращает Array[T]
, что означает, что должен быть создан новый массив и скопированы в него данные (следовательно, O(n)
), в отличие от List, который:
неизменяемый класс связанного списка
а это значит, что операция tail
должна быть очень быстрой (O(1)
).
Отвечает ли это на ваш вопрос? Выполнение хвостовой функции для массивов Scala