[英]Why is the runtime of this algorithm O(t)?
This is from problem 4.8 of Cracking the Coding Interview 6th edition.这是来自 Cracking the Coding Interview 6th edition 的问题 4.8。 The following code is one solution to the following prompt: "Find the first common ancestor of two nodes in a binary tree"
以下代码是以下提示的一种解决方案:“Find the first commonance of two nodes in a binary tree”
TreeNode commonAncestor(TreeNode root, TreeNode p, TreeNode q){
/* Checks if either node is not in the tree, or if one covers the other. */
if(!covers(root, p) || !covers(root, q)){
return null;
} else if (covers(p,q)){
return p;
} else if (cover(q,p)){
return q;
}
/* Traverse upwards until you find a node that covers q. */
TreeNode sibling = getSibling(p);
TreeNode parent = p.parent;
while(!covers(sibling, q)){
sibling = getSibling(parent);
parent = parent.parent;
}
return parent;
}
boolean covers(TreeNode root, TreeNode p){
if(node == null) return false;
if(root == p) return true;
return covers(root.left, p) || covers(root.right,p);
}
TreeNode getSibling(TreeNode node){
if(node == null || node.parent ==null){
return null;
}
TreeNode parent = node.parent;
return parent.left == node ? parent.right: parent.left;
}
The book says that "this algorithm takes O(t) time, where t is the size of the subtree for the first common ancestor. In the worst case this will be O(n)"这本书说“这个算法需要 O(t) 时间,其中 t 是第一个共同祖先的子树的大小。在最坏的情况下,这将是 O(n)”
However, aren't the calls to covers from root at the beginning of commonAncestor making the runtime O(d+t), d being the depth of the either p or q, depending on which one is deeper.然而,在 commonAncestor 开始时从根调用covers 不是使运行时O(d+t),d 是p 或q 的深度,这取决于哪个更深。
Well, it looks like cover(root,p)
will search the entire sub-tree rooted at x
, since it checks both root.left
and root.right
recursively.好吧,看起来
cover(root,p)
将搜索以x
为根的整个子树,因为它递归地检查root.left
和root.right
。
But yes, this problem can be solved in time O(d).但是是的,这个问题可以在 O(d) 时间内解决。 (Go up from each of
p
, q
to the root, and then just the first element the two lists have in common.) (从
p
, q
中的每一个上升到根,然后只是两个列表共有的第一个元素。)
Um, it looks like that code inside cover
is wrong, too, in a couple different ways:嗯,看起来
cover
里面的代码也是错误的,有几种不同的方式:
return false
rather than return null
when we've recurred "off the end" of a branch;return false
而不是return null
;if (root==p) return true
.if (root==p) return true
。 (One could be clever and modify the existing return
statement to be return (root==p) || covers(..,..) || covers(..,..)
.) return
语句修改为return (root==p) || covers(..,..) || covers(..,..)
。)You may want to review the part on Big O in the beginning of the book.您可能需要查看本书开头的 Big O 部分。 O(d+t) is somewhat accurate, but because that's a plus one of them (either d or t) is going to get bigger faster than the other.
O(d+t) 有点准确,但因为这是一个加号,其中一个(d 或 t)会比另一个更快地变大。 In this case, t = # of nodes in a subtree, and d = depth in the overall tree.
在这种情况下,t = 子树中的节点数,d = 整个树中的深度。 T is going to grow significantly faster than d.
T 将比 d 增长得更快。
As an illustration:举例说明:
1
/ \
2 3
/ \ / \
4 5 6 7
If We're looking at this tree and we want to know the common ancestor for 4 and 5:
t = 3
d = 3
if we want the common ancestor of 2 and 7 in the same tree then:
t = 7
d = 3
Due to the way trees work depth will always be equal to or smaller than the number of nodes.由于树的工作方式,深度将始终等于或小于节点数。 Therefore the time complexity will be average (big theta?) of t (# of nodes in subtree) and at worst (big o) n (#number of nodes in tree).
因此,时间复杂度将是 t(子树中的节点数)的平均值(大 theta?),最坏的情况是(大 o)n(树中的节点数)。
As an aside, the checks to root are going to do O(n) at the start which would make the whole thing O(n), but the author states that it does, in fact have O(n).顺便说一句,对 root 的检查将在开始时执行 O(n),这将使整个事情 O(n),但作者指出它确实如此,实际上有 O(n)。 "this algorithm takes O(t) time" is, I think, the author's analysis for average case.
“这个算法需要 O(t) 时间”是,我认为,作者对平均情况的分析。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.