Классическая задача дерева с использованием рекурсии.

В чем проблема?

Нам дан корень бинарного дерева, и задача состоит в том, чтобы найти максимальное значение 'v' такое, что 'v' равно абсолютной разнице между двумя узлами 'a' и 'b', где 'a' является предком из «б».

Проще говоря, узел-предок «а» может быть родителем, прародителем, прапрадедушкой и т. д. узла «b» — предок — это любой узел, который находится между корнем и этим узлом, например:

                                   8
                                 /   \
                                3     10
                               / \      \
                              1   6      14
                                 /  \    /
                                4    7  13

В приведенном выше дереве предками узла 7 являются 6, 3 и 8, поскольку эти узлы находятся на пути от корня (8) к узлу 7.

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

Подход:

Поскольку мы работаем с древовидной структурой и учитываем родственные связи, отличным подходом является использование поиска в глубину (DFS). Для каждого узла мы хотим знать:

  • наименьшее значение, которое мы видели до сих пор
  • самое большое значение, которое мы видели до сих пор

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

Вот пошаговая разбивка:

  • Начните с корневого узла. По мере того, как мы спускаемся по дереву, в каждом узле вычисляем абсолютную разницу между значением узла и минимальным и максимальным значениями, обнаруженными до сих пор. Это дает нам потенциальные ответы.
  • Обновите ответ с максимальным из этих различий.
  • Рекурсивно перемещайтесь по дереву, обновляя минимальное и максимальное значения, наблюдаемые до сих пор.

Код решения с построчным объяснением:

def dfs(node, min_val, max_val):
    # If the node is None (we've reached a leaf), we return the absolute difference between min_val and max_val.
    # This difference represents the maximum difference we've found in this particular path from root to leaf.
    if not node:
        return abs(max_val - min_val)
    
    # We update min_val and max_val with the current node's value.
    # This is because we're traversing down the tree, and we want to keep track of the smallest and largest values we've encountered so far.
    min_val = min(min_val, node.val)
    max_val = max(max_val, node.val)
    
    # We perform DFS for the left and right children of the current node.
    # For each child, we pass on the updated min_val and max_val. This lets each subtree know the smallest and largest values up to this point.
    # Each call to dfs will return the maximum absolute difference found in the corresponding subtree.
    left = dfs(node.left, min_val, max_val)
    right = dfs(node.right, min_val, max_val)
    
    # We want the single largest difference in the whole tree, so we return the maximum difference we found in either the left or the right subtree.
    return max(left, right)

# We start our DFS from the root node.
# Initially, we set our min_val to infinity and max_val to negative infinity since we haven't encountered any node yet.
return dfs(root, float('inf'), float('-inf'))

Только код решения:

def dfs(node, min_val, max_val):
    if not node:
        return abs(max_val - min_val)
    
    min_val = min(min_val, node.val)
    max_val = max(max_val, node.val)
    
    left = dfs(node.left, min_val, max_val)
    right = dfs(node.right, min_val, max_val)
    
    return max(left, right)

return dfs(root, float('inf'), float('-inf'))

Анализ сложности:

Временная сложность: O(n) — мы проходим каждый узел в дереве только один раз, поэтому временная сложность линейна по отношению к количеству узлов в дереве.

Пространственная сложность: O(h) — здесь мы используем рекурсивную поиск в глубину, и максимальная глубина рекурсии будет равна высоте дерева. Следовательно, сложность пространства будет пропорциональна высоте «h» дерева.

Если вам понравилась эта статья, рассмотрите возможность подписаться на меня, чтобы узнать больше. Ваши мысли и идеи важны для меня, и я приветствую любые предложения — чтобы сделать обмен вашими отзывами со мной еще проще, я создал быструю форму, доступ к которой вы можете получить здесь. Ваш вклад очень ценится! Не стесняйтесь обращаться к нам — ваше участие — это то, что делает это сообщество процветающим.

Спасибо за чтение и удачного кодирования! :)