Помогите решить задачу с кроликами (Swift)

swift
ios

#1

У вас имеется популяция кроликов.
Каждый кролик создает нового кролика каждые 5 дней.
Каждый кролик обозначен числом дней, оставшихся до создания нового кролика.
Новорожденным кроликам в первом цикле нужно больше времени перед тем как они готовы создавать новых кроликов – 3 дополнительных дня в первом цикле.

Например, предположим, у вас есть кролик, обозначенный числом 2.

  • Через 1 день, его обозначаемое число станет 1.
  • Еще через 1 день, его обозначаемое число станет 0.
  • Еще через один день, его обозначаемое число примет значение 4 (т.к. возраст относится к 0-индексации) и кролик создаст нового кролика с обозначенным числом 7.
  • Еще через день первый кролик сменит свое обозначаемое число на 3, а второй кролик сменит свое обозначаемое число на 6.

Ваши вводные данные = это список значений имеющихся кроликов на старте, разделенные запятой, например:

4,2,2,1


#2
func rabbits(_ input: String, _ days: Int) -> Int {
    var rabitsCash = [Int: Int]()
    return input
        .split(separator: ",")
        .compactMap { Int($0) }
        .map {
            if let value = rabitsCash[$0] {
                return value
            }
            let value = rabbitMultiplier(bDayCount: $0, days: days)
            rabitsCash[$0] = value
            return value
        }
        .reduce(0, +)
}

func rabbitMultiplier(
    bDayCount: Int,
    days: Int
) -> Int {
    let dif = days - (bDayCount + 1)
    if dif <= 0 { return 1 }
    return rabbitMultiplier(bDayCount: 4, days: dif) + rabbitMultiplier(bDayCount: 7, days: dif)
}

#4

Jack, вы просто гуру! Спасибо огромное!


#5

Джек, неудобно просить, если вдруг не сложно и будет время, не смогли бы закомментить основные ключевые моменты по коду, что делали и почему… Не смог полностью разобраться в логике… (
Еще раз заранее спасибо за помощь!


#6
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)
}

#7

Wow wow wow!!! x 100000 thanks за неравнодушие, открытость и науку для начинающих!