如何计算二进制子树查找空间复杂度
作者:互联网
这个问题来自Cracking the Coding Interview.我无法理解解决方案的空间复杂性.
问题:
你有两个非常大的二叉树:T1,有数百万个节点,T2,有数百个节点.创建一个算法来确定T2是否是T1的子树.
解决方案(在Java中):
public static boolean containsTree(TreeNode t1, TreeNode t2) {
if (t2 == null)
return true; // The empty tree is a subtree of every tree.
else
return subTree(t1, t2);
}
/* Checks if the binary tree rooted at r1 contains the binary tree
* rooted at r2 as a subtree somewhere within it.
*/
public static boolean subTree(TreeNode r1, TreeNode r2) {
if (r1 == null)
return false; // big tree empty & subtree still not found.
if (r1.data == r2.data) {
if (matchTree(r1,r2)) return true;
}
return (subTree(r1.left, r2) || subTree(r1.right, r2));
}
/* Checks if the binary tree rooted at r1 contains the
* binary tree rooted at r2 as a subtree starting at r1.
*/
public static boolean matchTree(TreeNode r1, TreeNode r2) {
if (r2 == null && r1 == null)
return true; // nothing left in the subtree
if (r1 == null || r2 == null)
return false; // big tree empty & subtree still not found
if (r1.data != r2.data)
return false; // data doesn’t match
return (matchTree(r1.left, r2.left) &&
matchTree(r1.right, r2.right));
}
该书称该解决方案的空间复杂度为O(log(n)log(m)),其中m是T1(较大树)中的节点数和T2中的n个节点数.
对我来说,似乎该解决方案具有O(log(m)* log(n))空间复杂度,因为“子树”函数具有log(n)递归调用,并且每个递归调用执行“matchTree”函数,该函数触发log(m)递归调用.
为什么这个解决方案O(log(n)log(m))的复杂性?
解决方法:
由于我们没有在堆上创建任何对象,因此空间复杂度就是堆栈的大小.所以问题不在于有多少总呼叫发生,而是堆栈有多大.
containsTree()只能调用subTree(),subTree()可以调用自身或matchTree(),而matchTree()只能调用自身.因此,在调用matchTree()的任何时候,堆栈如下所示:
[containsTree] [subTree] ... [subTree] [matchTree] ... [matchTree]
这就是为什么你不在这里乘以空间复杂性的原因:每次调用subTree()都可以调用matchTree(),那些对matchTree()的调用会在subTree()继续递归之前离开堆栈.
按照“正确答案”的分析
如果问题没有说明树是否平衡,那么真正的最坏情况分析会假设它们可能不是.但是,你和这本书都假设它们是.我们可以稍后将这个问题放在一边,说T1的深度为c,T2的深度为d.如果T1是平衡的,则c是O(log(m)),否则是O(m).对于T2来说同样的事情.
matchTree()的最坏情况是O(d),因为它可以递归到最远的是T2的高度.
subTree()的最坏情况是递归的O(c),因为它可以递归的最远的是T1的高度加上调用matchTree()的成本,总共为O(c d).
并且containsTree()只是在调用subTree()时添加一个常量,这样就不会改变空间复杂度.
因此,如果T1和T2都是平衡的,通过替换c和d可以看出O(log(m)log(n))似乎是合理的.
“正确答案”的问题
就像我之前说过的那样,假设二元树是平衡的,直到你知道它们是真实的,这是不对的.所以更好的答案可能是O(m n).
可是等等!问题是T2的大小小于T1的大小.这意味着n是O(m),log(n)是O(log(m)).那么为什么我们一直在浪费时间担心n?
如果树是平衡的,则空间复杂度仅为O(log(m)).在你不知道什么是平衡的一般情况下,真正的答案应该是O(m),即较大树的大小.
标签:java,algorithm,binary-tree,space-complexity 来源: https://codeday.me/bug/20190519/1137404.html