[英]Recursion related to trees
这是找到等于特定总和的根到叶路径的代码:
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语句?
这是一个很好的递归可视化 。 基本上,当你调用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。 希望这可以帮助。
实际上这没有以最清晰的方式编码。
递归始终是通过使用相同的过程(函数)来解决同一问题的一个或多个较小版本,然后组合这些解决方案来解决问题。
在这种情况下,较小的问题是检查左右子树中剩余的所需总和(如果存在)。
如果成功,我们可以在左侧停止,跳过右侧。 以这种方式,找到具有所需总和的树中的“最左边”路径。 我们没有必要找到任何其他人。
检查子树时,我们从所需的总和中减去当前节点的值。 直观地,这使得问题“如上所述”更小。
我将添加显示逻辑的注释。
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);
}
}
解释一个简单的例子可能有所帮
让我们考虑这样一棵树:
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.