这是找到等于特定总和的根到叶路径的代码:
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
if (root.left==null && root.right==null) {
return (sum == root.val);
}
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
即使一个递归调用返回true(使用return (sum==root.val)
),我也不明白原始函数调用是如何生效的。
我的理解是,在堆栈中,该特定的激活记录是真的,但是然后堆栈上的其他调用不会返回false;显然剩余的可能不是一条路径,并不会使它全部变为虚假?它如何重视if语句?
答案 0 :(得分:1)
这是递归的好visualisation。基本上,当你调用hasPathSum时,它会检查root是否为null。如果它为null,那么它将返回false。
如果root不为null,那么它会更进一步。如果左右两个都为空,则表示您处于叶节点。如果叶节点具有与根相同的值,那么您将返回true。否则就是假的。
如果两个if语句都被跳过,则表示左侧或右侧(或两者)有更多节点。然后根节点将成为你的左边和右边,你将检查那里的和值,并返回它们的结果。
我们假设这是你的树,leaf4有所需的值:
root
left right
leaf1 - leaf3 leaf4
----------- 1st depth, with root node ---------------
hasPathSum(root)
root==null //false, so it moves on
root.left // is 'left', so skipping
hasPathSum(left) || hasPathSum(right) // this statement will be evaluated
------------- 2nd depth, with left node ---------------
hasPathSum(left)
left==null //false, so it moves on
left.left // is 'leaf1', so skipping
hasPathSum(leaf) || hasPathSum(null) // this statement will be evaluated
------------- 3rd depth, with leaf1 node ---------------
hasPathSum(leaf1)
leaf1==null //false, so it moves on
leaf1.left and leaf1.right // are both null, so returnin with sum == root.val
------------- 3rd depth, with - node ---------------
hasPathSum(-)
-==null //true, so it returns with false
------------- 2nd depth, with left node ---------------
false || false // is false, so it will return with false
------ in this moment, hasPathSum(left) part of 1st depth's has been evaulated to false
so hasPathSum(right) has to be ecaluated as well.
它与上面的代码没有任何不同,除了处理leaf4时,sum == root.val将为true,因此整个事件将返回true。希望这会有所帮助。
答案 1 :(得分:1)
这实际上没有以最清晰的方式编码。
递归始终是通过使用相同的过程(函数)来解决同一问题的一个或多个较小版本,然后组合这些解决方案来解决问题。
在这种情况下,较小的问题是在左右子树(如果存在)中检查剩余的所需总和。
如果成功,我们可以在左边停止,跳过右边。以这种方式,找到具有所需总和的树中的“最左边”路径。我们没有必要找到任何其他人。
检查子树时,我们从所需的总和中减去当前节点的值。直观地说,这使问题“变小”如上所述。
我会添加显示逻辑的评论。
public boolean hasPathSum(TreeNode root, int sum) {
// If we've reached a null child, the other child is non-null, so we're
// not at a leaf, so there no way this can be a leaf-to-path sum.
// See below for why this is the case.
if (root == null) {
return false;
}
// If we're at a leaf (null children), then we've found the path
// if and only if the node value exactly equals the sum we're looking for.
if (root.left == null && root.right == null) {
return (sum == root.val);
}
// We're not at a leaf. See if we can find the remaining part of the sum
// by searching the children. Null children are handled above. If the
// sum is found in the left subtree, the short-circuit evaluation of ||
// will skip searching the right.
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
请注意,
可能没有意义hasPathSum(null, 0)
在此代码中返回false。我这样做:
class TreeNode {
// ... skipping other TreeNode fields.
public boolean isLeaf() { return left == null && right == null; }
public boolean hasPathSum(int sum) {
return isLeaf() ? sum == val :
(left != null && left.hasPathSum(sum - val)) ||
(right != null && right.hasPathSum(sum - val);
}
}
答案 2 :(得分:0)
解释的一个简单例子可能有所帮助。
让我们考虑一下这样的树:
5
/ \
2 3
\
1
我们正在寻找9的总和。
现在递归调用将如下所示:
(我的缩进是这样的,每个语句都由前一个缩进级别的函数执行)
hasPathSum(N5, 9)
hasPathSum(N2, 9-5 = 4)
return false // since 2 != 4
hasPathSum(N3, 9-5 = 4)
hasPathSum(null, 4-3 = 1) // left child of N3
return false // since root == null
hasPathSum(N1, 4-3 = 1)
return true // since 1 == 1
return (false || true) = true
return (false || true) = true