awesome-everything EN
↑ Обратно к восхождению

Алгоритмы с нуля

Деревья: чтение кода и трассировка

Суть Прочитай четыре небольших сниппета про деревья — traversal, багованный валидатор BST, рекурсивную высоту и tree DP для суммы пути — и предскажи вывод или назови фикс с наибольшим рычагом.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min

Баги в деревьях прячутся в порядке двух рекурсивных вызовов и в разнице между локальной проверкой и глобальной. Прочитай каждый сниппет, прогони его в голове и выбери, что внимательный инженер заключит или починит первым.

Цель

Потренируй главную петлю чтения кода деревьев: предскажи точный вывод traversal, заметь баг «на одно поддерево» в валидаторе BST, разбери базовый случай рекурсивной высоты и распознай, когда возвращаемое значение tree DP должно отличаться от ответа.

Сниппет 1 — порядок traversal

function walk(node) {
  if (node === null) return;
  walk(node.left);
  console.log(node.value);
  walk(node.right);
}

//        5
//       / \
//      3   8
//     / \   \
//    2   4   9
walk(root);
Викторина

Какую точную последовательность это печатает и что это за traversal?

Сниппет 2 — баг валидатора BST

function isBST(node) {
  if (node === null) return true;
  if (node.left && node.left.value >= node.value) return false;
  if (node.right && node.right.value <= node.value) return false;
  return isBST(node.left) && isBST(node.right);
}

//        5
//       / \
//      3   8
//         /
//        4      // 4 < 5, но сидит в ПРАВОМ поддереве 5
Викторина

Этот валидатор возвращает true для дерева выше, которое НЕ является корректным BST. В чём баг?

Сниппет 3 — рекурсивная высота

function height(node) {
  if (node === null) return 0;       // заметь: возвращает 0, не -1
  return 1 + Math.max(height(node.left), height(node.right));
}

// одиночный лист
console.log(height(leaf));
Викторина

При базовом случае null, возвращающем 0, что печатает height(leaf) и какое соглашение это подразумевает?

Сниппет 4 — tree DP для суммы пути

function maxPathSum(root) {
  let best = -Infinity;
  function gain(node) {
    if (node === null) return 0;
    const left = Math.max(gain(node.left), 0);   // отбросить отрицательные ветви
    const right = Math.max(gain(node.right), 0);
    best = Math.max(best, node.value + left + right);  // путь ЧЕРЕЗ узел
    return node.value + Math.max(left, right);          // путь, который родитель может продлить
  }
  gain(root);
  return best;
}
Викторина

Почему gain() возвращает node.value + max(left, right), а best обновляется через node.value + left + right?

Итог

Чтение кода деревьев сводится к нескольким рефлексам: найди строку посещения относительно двух рекурсивных вызовов, чтобы назвать traversal (и помни, что in-order на BST отсортирован); никогда не доверяй валидатору BST, который проверяет только родитель-против-ребёнка — корректность требует передаваемой границы (min, max); читай базовый случай null, чтобы понять, считается ли высота в узлах (возврат 0) или в рёбрах (возврат -1); и в tree DP следи за намеренным разрывом между тем, что узел возвращает родителю (одна продлеваемая ветвь), и тем, что он вносит в глобальный ответ (полный изгиб через него).

Продолжить восхождение ↑Деревья: собери BST-тулкит
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.