Бинарное дерево hasPathSum () Реализация - PullRequest
4 голосов
/ 18 ноября 2010

Привет, я пытаюсь реализовать hasPathSum() средство для данного числа, существует ли какой-либо путь между узлом от корня к листу.

Я получил этот код с веб-сайта Стэнфорда.И я думаю, что это неправильно

/** 
 Given a tree and a sum, returns true if there is a path from the root 
 down to a leaf, such that adding up all the values along the path 
 equals the given sum. 
 Strategy: subtract the node value from the sum when recurring down, 
 and check to see if the sum is 0 when you run out of tree. 
*/ 

boolean hasPathSum(Node node, int sum) { 
  // return true if we run out of tree and sum==0 
  if (node == null){ 
    return(sum == 0); 
  } 
  else { 
  // otherwise check both subtrees 
    int subSum = sum - node.data; 
    return(hasPathSum(node.left, subSum) || hasPathSum(node.right, subSum)); 
  } 

Это правильная реализация?

Я думаю, что это , если должно быть

  • if (node.left == null && node.right == null)

Если я не прав Пожалуйста, устраните мою путаницу

рассмотрите этот случай:

          5
         / \
        2   1
       /    
      3

-Спасибо

Ответы [ 6 ]

4 голосов
/ 18 ноября 2010

Так как Берт не исправляет свой ответ, я выложу правильный.

Да, вы правы, что исходный код не работает, несмотря на то, что большинство людей здесь говорят. В вашем примере

      5
     / \
    2   1
   /    
  3

Calling

hasPathSum(root, 7);

вернет true, несмотря на тот факт, что нет пути от корня к листу, который добавляет к 7. Это потому, что когда достигается узел 2, он рекурсивно проверяет правого потомка (с суммой 0), который возвращает true, потому что правильный ребенок - null.

Исправление основано на ответе Берта:

// `if` statement should check children and `return` statement deduct node.data from sum
boolean hasPathSum(Node node, int sum) { 
  int subSum = sum - node.data; 
  if(node.left==null && node.right==null) { 
    return(subSum == 0); 
  } 
  else { 
    // otherwise check both subtrees 
    if ( node.left != null && hasPathSum(node.left, subSum) ) {
        return true;
    if ( node.right != null && hasPathSum(node.right, subSum) ) {
        return true;
    }
    return false;
  } 
}

Вы можете свернуть блок else в одно длинное выражение, если хотите (много ands и ors), но я нахожу это чище.

4 голосов
/ 18 ноября 2010

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

Я считаю, что исходный код не работает для hasPathSum(tree, 7), потому что узел 2 не является листом.

Edit:

Оригинальный код изъят из-за явных ошибок - очевидных по крайней мере для всех, кроме меня: -)

Редактировать:

Мое новое решение ниже. Обратите внимание, что включенная оптимизация (if (sum <= node.data)) предполагает, что дерево состоит из всех положительных значений данных . Его следует удалить или настроить, если дерево имеет нулевые или отрицательные значения данных. (спасибо @Mark Peters).

Также обратите внимание на обсуждение в ответе комментариев по поводу обработки hasPathSum(null, 0).

static boolean hasPathSumBert(final Node node, final int sum) {
    // return true if we run out of tree and sum==0
    if (node == null) {                                   // empty tree
        // choose one:
        return (sum == 0);
        //return false;
    } else if (node.left == null && node.right == null) { // leaf
        return (sum == node.data);
    } else if (sum <= node.data) {                        // sum used up
        return false;
    } else {                                              // try children
        return (node.left != null  && hasPathSumBert(node.left, sum - node.data)) ||
               (node.right != null && hasPathSumBert(node.right, sum - node.data));
    }
}

Полный код:

public class TreeTest {
    static class Node {
        int data;
        Node left;
        Node right;

        Node(final int data, final Node left, final Node right) {
            this.data = data;
            this.left = left;
            this.right = right;
        }
    }

    public static void main(final String[] args) {
        final Node three = new Node(3, null, null);

        final Node two = new Node(2, three, null);
        final Node one = new Node(1, null, null);

        final Node five = new Node(5, two, one);
        final Node tree = five;

        for (int i = 0; i <= 10; i++) {
            System.out.println(i + "");
            System.out.println("original = " + hasPathSum(tree, i));
            System.out.println("bert     = " + hasPathSumBert(tree, i));
            System.out.println("mark     = " + hasPathSumMark(tree, i));
            System.out.println();
        }

        System.out.println("hasPathSumBert(null, 0): "+ hasPathSumBert(null, 0));
        System.out.println("hasPathSumBert(null, 1): "+ hasPathSumBert(null, 1));
    }

    static boolean hasPathSum(final Node node, final int sum) {
        // return true if we run out of tree and sum==0
        if (node == null) {
            return (sum == 0);
        } else {
            // otherwise check both subtrees
            final int subSum = sum - node.data;
            return (hasPathSum(node.left, subSum) || hasPathSum(node.right, subSum));
        }
    }

    static boolean hasPathSumBert(final Node node, final int sum) {
        // return true if we run out of tree and sum==0
        if (node == null) {                                   // empty tree
            // choose one:
            return (sum == 0);
            //return false;
        } else if (node.left == null && node.right == null) { // leaf
            return (sum == node.data);
        } else if (sum <= node.data) {                        // sum used up
            return false;
        } else {                                              // try children
            return (node.left != null  && hasPathSumBert(node.left, sum - node.data)) ||
                   (node.right != null && hasPathSumBert(node.right, sum - node.data));
        }
    }

    static boolean hasPathSumMark(final Node node, final int sum) {
        final int subSum = sum - node.data;
        if (node.left == null && node.right == null) {
            return (subSum == 0);
        } else {
            // otherwise check both subtrees
            if (node.left != null  && hasPathSumMark(node.left, subSum))
                return true;
            if (node.right != null && hasPathSumMark(node.right, subSum))
                return true;
            return false;
        }
    }
}

Образец прогона: (Примечание к случаю 7)

0
original = false
bert     = false
mark     = false

1
original = false
bert     = false
mark     = false

2
original = false
bert     = false
mark     = false

3
original = false
bert     = false
mark     = false

4
original = false
bert     = false
mark     = false

5
original = false
bert     = false
mark     = false

6
original = true
bert     = true
mark     = true

7
original = true
bert     = false
mark     = false

8
original = false
bert     = false
mark     = false

9
original = false
bert     = false
mark     = false

10
original = true
bert     = true
mark     = true

hasPathSumBert(null, 0): true
hasPathSumBert(null, 1): false
0 голосов
/ 06 сентября 2016

попробуйте

   bool hasPathSum(struct node* node, int sum){
        if(node == NULL){       
           return false;  
        }
        if((sum - (node->data) == 0) && (node->left == NULL) && (node->right == NULL) ) {    
            return true;  
        }
        if (sum - (node->data) < 0)  { 
            return false;  
        } else {       
            return( hasPathSum (node->left,sum - ( node->data ) ) || hasPathSum (node->right, sum - (node->data) ) );  
        }
   }
0 голосов
/ 18 января 2015

Вот альтернативный подход, который вычисляет сумму каждого пути и сопоставляет ее с целевым значением. ИМХО, это кажется более интуитивным, чем использование логики подсумов.

Кроме того, список чисел будет хранить суммы всех путей от корня к листу. Я добавил это только для того, чтобы убедиться, что мой код не генерирует никаких нежелательных путей.

public static boolean hasPathSum(Node root, int sum, int val, ArrayList<Integer> nums) {
    if(root == null) {
        return (sum == 0);
    }

    val = val + root.data;

    if(root.right == null && root.left == null) {
        nums.add(val);
        return (val == sum);
    }

    boolean left = hasPathSum(root.left, sum, val, nums);
    boolean right = hasPathSum(root.right, sum, val, nums);

    return left || right;

}
0 голосов
/ 24 февраля 2011

Функция OP явно не работает в следующем простом случае:

   1
    \
     2

Вышеупомянутое дерево как простой путь от корня к листу суммы 3. Но функция OP вернет true для hasPathSum(root,1)

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

Функция OP обрабатывает любой узел с NULL child как лист.

Следующая функция (такая же, как у Марка + еще одна проверка) исправляет это:

boolean hasPathSum(Node node, int sum) {
        // CASE 1: empty tree.
        if (node == NULL) {
                return sum == 0;
        }
        // CASE 2: Tree exits.
        int subSum = sum - node.data;
        // CASE 2A: Function is called on a leaf node.
        if (node.left==null && node.right==null) {
                return subSum == 0;
        // CASE 2B: Function is called on a non-leaf node.
        } else {
                // CASE 2BA: Non-left node has desired path in left subtree.
                if (node.left != null && hasPathSum(node.left, subSum) ){
                        return true;
                }
                // CASE 2BB: Non-left node has desired path in right subtree.
                if ( node.right != null && hasPathSum(node.right, subSum) ) {
                        return true;
                }
                // CASE 2BC: Non-left node has no desired pat.
                return false;
        }
}

C версия: Ideone Link

0 голосов
/ 19 ноября 2010

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

на самом деле я реализовал более простой способ, так чтоЭто может быть понятно каждому


Есть четыре случая, чтобы проверить

  1. , являются ли оба ребенка нулевыми (наш целевой случай)
  2. если существует только правый дочерний элемент (означает, что левый дочерний элемент равен нулю)
  3. если существует только левый дочерний элемент (означает, что правый дочерний элемент равен нулю)
  4. , если существуют оба дочерних элемента (означает, что узел имеет левый и правыйchilds)

Один особый случай : если вы передаете входное дерево непосредственно как ноль, то требуется обработать (еще один, если требуется блок)

    public static boolean hasPathSum(TNode root, int sum)
{
    if(root==null) //it is called only if you pass directly null
    return false;

    int subsum = sum-root.data;
    //if(subsum<0) return false; //uncomment this for reducing calls for negative numbers
    if(root.left==null && root.right==null) //for leaf node
    return (subsum==0);

    if(root.left==null) //if only right child exist
    return hasPathSum(root.right, subsum);

    if(root.right==null)//if only left child exist
    return hasPathSum(root.left, subsum);

    return (hasPathSum(root.left, subsum) || hasPathSum(root.right,subsum));
}

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

-Спасибо

...