二叉树hasPathSum()实现

时间:2010-11-18 12:43:40

标签: java algorithm data-structures tree binary-tree

您好 我正在尝试实施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

-Thanks

6 个答案:

答案 0 :(得分:4)

你真的应该只编码并尝试它 - 你会学到很多东西。 (编辑:我当然是......

我认为hasPathSum(tree, 7)的原始代码失败,因为节点2不是叶子。

修改

原始代码由于明显的错误而被撤销 - 至少对我而言显而易见: - )

修改:

我的新解决方案如下。请注意,包含的优化(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

答案 1 :(得分:4)

由于伯特没有修正他的答案,我会发布正确答案。

是的,尽管大多数人都在说,原始代码已被破坏,你说得对。在你的例子中

      5
     / \
    2   1
   /    
  3

调用

hasPathSum(root, 7);

将返回true,尽管没有添加到7的root-to-leaf路径。这是因为当到达节点2时,它会以递归方式检查正确的子节点(使用sum 0) ),然后返回true,因为正确的孩子是null

修正案的灵感来自Bert的回答:

// `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;
  } 
}

如果你想要(很多ands和ors),你可以将else块转换成一个长语句,但我发现它更干净。

答案 2 :(得分:0)

你好 谢谢你的回答,这个讨论似乎非常有趣, 昨晚我再次试图实现这个功能,我认为我的解决方案适用于所有情况,

实际上我以更简单的方式实施,以便每个人都可以理解


有四种情况需要检查

  1. 如果两个孩子都为空(我们的目标案例)
  2. 如果只有正确的孩子存在(意味着左孩子为空)
  3. 如果只剩下孩子(意味着右孩子为空)
  4. 如果两个孩子都存在(意味着节点有左右孩子)
  5. 一个特殊情况:如果直接将输入树作为null传递,则需要处理(如果是块请求,则需要处理一个)

        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));
    }
    

    请查看我的代码 这适用于所有二叉树案例吗?和 如果需要进行任何更改,请与我们联系。

    -Thanks

答案 3 :(得分:0)

对于以下简单案例,OP的功能明显失败:

   1
    \
     2

上面的树只是总和3的叶子路径的一个根。但OP的函数将在hasPathSum(root,1)

时返回true

这是因为仅当我们到达叶节点(空左子树和空右子树)或空树的特殊情况时,才应将变化的子和与零进行比较。

OP的功能是将NULL子节点视为叶子。

以下功能(与Mark的+另外一项检查相同)修复了它:

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

答案 4 :(得分:0)

这是另一种计算每条路径之和的方法,并将其与目标值相匹配。恕我直言,这似乎比使用子词的逻辑更直观。

此外,nums列表将存储所有根到叶路径的总和。我添加这个只是为了确保我的代码没有生成任何不需要的路径。

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;

}

答案 5 :(得分:0)

试试这个

   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) ) );  
        }
   }