import Foundation
func rabbits(_ input: String, _ days: Int) -> Int {
// Кеш кроликов, так как для двух кроликов с одинаковым возрастом будет одно возвращаемое число,
// так мы экономим время на расчетах но за это платим доп. памятью
// Испуользуем словарь, так как поиск в нем занимает O(1)
var rabitsCash = [Int: Int]()
return input
// Разделяет строку "1,2,3" в массив строк ["1", "2", "3"]
.split(separator: ",")
// Учитывая что конструктор @inlinable public init?(_ description: String) возвращает Int?
// нам нужно его безопасно развернуть, поэтому используем compactMap а не map
// т.е. на вход получаем строку из массива в предыдущем шаге, например "1" возвращаем Int - 1 и так для каждого элемента
// в итоге ["1", "2", "3"] -> [1, 2, 3]
.compactMap { Int($0) }
// Здесь мы преобразуем наше число из предыдущего шага в количество кроликов с помощью ф-и `rabbitMultiplier`
// Предварительно смотрим в кеш, может мы уже посчитали для кролика с таким возрастом количество дней
.map {
if let value = rabitsCash[$0] {
return value
}
let value = rabbitMultiplier(bDayCount: $0, days: days)
rabitsCash[$0] = value
return value
}
// Скрадываем все результаты, условно, наша входная строка(возрастов) "1,2,3" превратилась в массив(количества кроликов) [12, 44, 99]
// т.е. кролик с временем жизни в 1 день, за n дней напрлоданосил 12 кроликов
.reduce(0, +)
}
func rabbitMultiplier(
bDayCount: Int,
days: Int
) -> Int {
// Считаем разницу между всем количеством дней до появления нового кролика
let dif = days - (bDayCount + 1)
// Если количество дней до появления нового кролика <= 0 то он не успеет появиться
if dif <= 0 { return 1 }
// Вызываем этот метод снова, пока не выполнится услови выше, только добавляем нового кролика, посмотрите как работают рекурсии
return rabbitMultiplier(bDayCount: 4, days: dif) + rabbitMultiplier(bDayCount: 7, days: dif)
}