Подтвердить что ты не робот

Поиск путей в суммировании двоичного дерева поиска до целевого значения

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

Например, в следующем двоичном дереве поиска:

  2
 / \ 
1   3 

когда сумма должна быть 6, следует напечатать путь 1 -> 2 -> 3.

4b9b3361

Ответ 1

Пройдите через дерево из корня и выполните сборку по порядку всех сумм пути. Используйте хеш-таблицу, чтобы сохранить возможные пути, основанные на node и только вниз. Мы можем построить все пути, проходящие через node от себя и к его детским путям.

Вот psuedo-код, который реализует выше, но хранит только суммы, а не фактические пути. Для самих путей вам нужно сохранить конец node в хэш-таблице (мы знаем, где он начинается, и есть только один путь между двумя узлами в дереве).

function findsum(tree, target)
  # Traverse the children
  if tree->left
    findsum(tree.left, target)
  if tree->right
    findsum(tree.right, target)

  # Single node forms a valid path
  tree.sums = {tree.value}

  # Add this node to sums of children
  if tree.left
    for left_sum in tree.left.sums
      tree.sums.add(left_sum + tree.value)
  if tree.right
    for right_sum in tree.right.sums
      tree.sums.add(right_sum + tree.value)

  # Have we formed the sum?
  if target in tree.sums
    we have a path

  # Can we form the sum going through this node and both children?
  if tree.left and tree.right
    for left_sum in tree.left.sums
      if target - left_sum in tree.right.sums
        we have a path

  # We no longer need children sums, free their memory
  if tree.left
    delete tree.left.sums
  if tree.right
    delete tree.right.sums

Это не использует тот факт, что дерево является деревом поиска, поэтому оно может применяться к любому двоичному дереву.

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

Ответ 2

Мой ответ O(n^2), но я считаю, что он является точным и имеет несколько иной подход и выглядит проще.

Предположим, что значение, сохраненное в node i, обозначается символом VALUE[i]. Моя идея состоит в том, чтобы хранить в каждой node сумму значений на пути от root до этого node. Поэтому для каждого node i, SUM[i] представляет собой сумму пути от root до node i.

Затем для каждой пары node (i,j) найдите своего общего предка k. Если SUM(i)+SUM(j)-SUM(k) = TARGET_SUM, вы нашли ответ.

Это O(n^2), поскольку мы перебираем все пары node. Хотя, мне жаль, что я не смогу найти лучший способ, чем просто собрать все пары.

Мы могли бы немного его оптимизировать, отбросив поддеревья, где value node, внедренный в поддерево, больше, чем TARGET_SUM. Любые дальнейшие оптимизации приветствуются:)

Psuedocode:

# Skipping code for storing sum of values from root to each node i in SUM[i]
for i in nodes:
    for j in nodes:
        k = common_ancestor(i,j)
        if ( SUM[i] + SUM[j] - SUM[k] == TARGET_SUM ):
            print_path(i,k,j)

Функция common_ancestor является довольно стандартной проблемой для двоичного дерева поиска. Psuedocode (из памяти, надеюсь, ошибок нет!):

sub common_ancestor (i, j):
  parent_i = parent(i)
  # Go up the parent chain until parent value is out of the range. 
  # That a red flag.
  while( VAL[i] <= VAL[parent_i] <= VAL[j] ) : 
    last_parent = parent_i
    parent_i = parent(i)
    if ( parent_i == NULL ): # root node
      break
return last_parent

Ответ 3

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

  public static List<ArrayList<Integer>> pathSum(Node head, int sum) {
    List<Integer> currentPath = new ArrayList<Integer>();
    List<ArrayList<Integer>> validPaths = new ArrayList<ArrayList<Integer>>();

    dfsSum(head, sum, currentPath, validPaths);

    return validPaths;
  }

  public static void dfsSum(Node head, int sum, List<Integer> currentPath, List<ArrayList<Integer>> validPaths) {
    if (head == null) return;

    currentPath.add(head.val);

    if (head.left == null && head.right == null && sum == head.val) {
      validPaths.add(new ArrayList<Integer>(currentPath));
    }

    dfsSum(head.left, sum - head.val, new ArrayList<Integer>(currentPath), validPaths);
    dfsSum(head.right, sum - head.val, new ArrayList<Integer>(currentPath), validPaths);
  }

И класс node:

class Node {
    public int val;
    public Node left;
    public Node right;

    public Node(int val) {
      this.val = val;
    }
  }