Вопрос: Напишите функцию, которая возвращает степень X ^ Y (не используйте встроенные функции).

Например, учитывая 2 ^ 10, вернуть 1024,

Например, учитывая 10 ^ 2, вернуть 100.

Подсказки:

- Вы можете сделать это через рекурсивную функцию,

- Каковы базовые случаи?,

- Что делать, если мощность нечетное число.

Решение:

func power(radix: Int, power: Int) -> Int {
    // 1.
    var memo = [Int: Int]()
    return powerMemo(radix: radix, power: power, memo: &memo)
}

// 2.
func powerMemo(radix: Int, power: Int, memo: inout [Int: Int]) -> Int {
    // 3.
    guard radix != 0 else { return 0 }
    guard power >= 0 else { return 0 }
    guard power != 0 else { return 1 }
    guard power != 1 else { return radix }

    if let value = memo[power] {
        // 4.
        return value
    } else {
        // 5.
        let value = powerMemo(radix: radix, power: power / 2, memo: &memo)
                  * powerMemo(radix: radix, power: power / 2, memo: &memo)
                  * (power % 2 == 0 ? 1 : radix)
        // 6.
        memo[power] = value
        return value
    }
}

Пояснения:

1. Давайте создадим частичный результат для мемоизации и передадим его помощнику функции.

var memo = [Int: Int]()
return powerMemo(radix: radix, power: power, memo: &memo)

2. Это вспомогательная функция, которая является рекурсивной и создает частичные результаты, пока мы не найдем целевой результат.

func powerMemo(radix: Int, power: Int, memo: inout [Int: Int]) -> Int {

3. Это базовые случаи для мощности, основание == 0, мощность ‹= 1 (здесь мы не рассматриваем отрицательную мощность).

guard radix != 0 else { return 0 }
guard power >= 0 else { return 0 }
guard power != 0 else { return 1 }
guard power != 1 else { return radix }

4. Если значения уже рассчитаны, возвращаем сохраненный результат.

if let value = memo[power] {
  return value

5. Поскольку X²N == X^N * X^N, мы можем рекурсивно и уменьшить число мощности (разделить на два и позаботиться о числах степени шансов) до достижения одного из базовых случаев.

let value = powerMemo(radix: radix, power: power / 2, memo: &memo)
            * powerMemo(radix: radix, power: power / 2, memo: &memo)
            * (power % 2 == 0 ? 1 : radix)

6. Сохраним текущий результат и вернем его.

    memo[power] = value
    return value
  }
}

Сложность:

- Временная сложность: поскольку мы каждый раз уменьшаем задачу на два, как при бинарном поиске, временная сложность равна O(log y), где y - мощность,

- Пространственная сложность: стек вызовов и словарь частичных результатов составляют временную сложность O(y).

Тест-кейсы:

public func testPower() {
  assert(power(radix: 2, power: 10) == 1024, "power 1 not equal")
  assert(power(radix: 10, power: 2) == 100, "power 2 not equal")
}

Следовать за:

Сделайте это итеративным или используйте табуляцию (или сделайте и то, и другое!).

‹‹ Структуры данных, алгоритмы и вопросы для интервью ››