Вопрос: Создайте функции для сериализации и десериализации бинарного дерева (объект -> строка и строка -> объект).

   20
  / \
 10  15
 /  / \
13  9 8

Первая функция должна возвращать строку, представляющую данное дерево, а вторая должна принимать ту же строку для восстановления исходного дерева.

Подсказки:

- Для просмотра узлов вы можете использовать DFS,

- Вам нужно преобразовать значение узла, но также и нулевой узел,

- Десериализация — это обратная логика сериализации.

Решение:

// 1.
func serializeBinaryTree(binaryNode: BinaryNode<Int>?) -> String {
    // 2.
    guard let binaryNode = binaryNode else { return "" }

    // 3.
    var ouput = ""
    serializeBinaryTree(binaryNode: binaryNode, ouput: &ouput)

    // 4.
    ouput.removeLast()
    return ouput
}

func serializeBinaryTree(binaryNode: BinaryNode<Int>?, ouput: inout String) {
    // 5.
    guard let binaryNode = binaryNode else {
        ouput += "null-"
        return
    }

    // 6.
    ouput += "\(binaryNode.value)-"

    // 7.
    serializeBinaryTree(binaryNode: binaryNode.left, ouput: &ouput)
    serializeBinaryTree(binaryNode: binaryNode.right, ouput: &ouput)
}

// 8.
func deserializeBinaryTree(string: String) -> BinaryNode<Int>? {
    // 9.
    guard !string.isEmpty else { return nil }

    // 10.
    var array = string.components(separatedBy: "-")

    // 11.
    let result = deserializeBinaryTree(array: &array)
    return result
}

private func deserializeBinaryTree(array: inout [String]) -> BinaryNode<Int>? {
    // 12.
    guard !array.isEmpty else { return nil }

    // 13.
    guard let value = Int(array.removeFirst()) else {
        return nil
    }

    // 14.
    let binaryNode = BinaryNode<Int>(value: value)
    binaryNode.left = deserializeBinaryTree(array: &array)
    binaryNode.right = deserializeBinaryTree(array: &array)

    // 15.
    return binaryNode
}

Пояснения:

1. Начнем с сериализации бинарного дерева (объект -> строка).

func serializeBinaryTree(binaryNode: BinaryNode<Int>?) -> String {

2. Если заданный узел равен нулю, вернуть пустую строку.

guard let binaryNode = binaryNode else { return “” }

3. Давайте создадим результирующую пустую строку и вызовем вспомогательный метод с корневым узлом и вновь созданной пустой строкой.

var ouput = “”
serializeBinaryTree(binaryNode: binaryNode, ouput: &ouput)

4. Удалите последний дефис (разделитель узлов), так как он бесполезен, и верните строку.

ouput.removeLast()
return ouput

5. Если данный узел нулевой, добавьте тег «null» и разделитель «-» (это базовый случай для рекурсии).

guard let binaryNode = binaryNode else {
  ouput += "null-"
  return
}

6. В противном случае добавьте значение узла и разделитель «-».

ouput += “\(binaryNode.value)-”

7. Рекурсивно вызывать левый и правый узлы.

serializeBinaryTree(binaryNode: binaryNode.left, ouput: &ouput)
serializeBinaryTree(binaryNode: binaryNode.right, ouput: &ouput)

8. Продолжим десериализацию бинарного дерева (строка -> Объект).

func deserializeBinaryTree(string: String) -> BinaryNode<Int>? {

9. Если строка пуста, вернуть nil.

guard !string.isEmpty else { return nil }

10. Разделим строку по разделителю «-» на массив.

var array = string.components(separatedBy: “-”)

11. Вызовем хелпер метода с только что созданным массивом и вернем полученный узел.

let result = deserializeBinaryTree(array: &array)
return result

12. Если массив пуст, вернуть nil (это базовый случай для рекурсии).

guard !array.isEmpty else { return nil }

13. Возьмем первое значение из массива и удалим его.

guard let value = Int(array.removeFirst()) else {
  return nil
}

14. Создайте новый узел с полученным значением и присвойте результат рекурсии его левому и правому узлу.

let binaryNode = BinaryNode<Int>(value: value)
binaryNode.left = deserializeBinaryTree(array: &array)
binaryNode.right = deserializeBinaryTree(array: &array)

15. В конце концов, верните новый узел.

return binaryNode

Сложность:

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

- Сложность пространства: размер выходной строки пропорционален размеру дерева, тогда сложность пространства будет линейной O(n), где n - количество узлов.

Тест-кейсы:

public func testSerializeBinaryTree() {
  // 20
  // / \
  // 10 15
  // / / \
  // 13 9 8
  //
  let binaryNode20 = BinaryNode<Int>(value: 20)
  let binaryNode10 = BinaryNode<Int>(value: 10)
  let binaryNode15 = BinaryNode<Int>(value: 15)
  let binaryNode13 = BinaryNode<Int>(value: 13)
  let binaryNode09 = BinaryNode<Int>(value: 09)
  let binaryNode08 = BinaryNode<Int>(value: 08)
  let binaryTree = binaryNode20
  binaryTree.left = binaryNode10
  binaryTree.right = binaryNode15
  binaryNode10.left = binaryNode13
  binaryNode15.left = binaryNode09
  binaryNode15.right = binaryNode08

  let serializedBinaryTree = serializeBinaryTree(binaryNode: binaryTree)
  let newBinaryTree = deserializeBinaryTree(string: serializedBinaryTree)

  assert(binaryTree.value == newBinaryTree?.value, "binaryTree.value not equal")
  assert(binaryTree.left?.value == newBinaryTree?.left?.value, "binaryTree.left?.value not equal")
  assert(binaryTree.right?.value == newBinaryTree?.right?.value, "binaryTree.right?.value not equal")
  assert(binaryTree.left?.left?.value == newBinaryTree?.left?.left?.value, "binaryTree.left?.left?.value not equal")
  assert(binaryTree.left?.right?.value == newBinaryTree?.left?.right?.value, "binaryTree.left?.right?.value not equal")
  assert(binaryTree.right?.left?.value == newBinaryTree?.right?.left?.value, "binaryTree.right?.left?.value not equal")
  assert(binaryTree.right?.right?.value == newBinaryTree?.right?.right?.value, "binaryTree.right?.right?.value not equal")
}

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

Нет дополнительного вопроса.

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



Повышение уровня кодирования

Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:

  • 👏 Хлопайте за историю и подписывайтесь на автора 👉
  • 📰 Смотрите больше контента в публикации Level Up Coding
  • 🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"

🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу