Algorithm 如何在完全二叉树的最后一级找到最右节点的位置?
我在二叉树中做一个问题,当我遇到一个问题,在一个完整的二叉树的最后一级找到最右边的节点,这里的问题是我们必须在O(n)时间内完成它,这是一个停止点,在O(n)中完成它很简单,通过遍历所有元素,但是有没有一种方法可以在小于O(n)的复杂度下完成这项工作,我在网上浏览了很多次,但我找不到关于这件事的任何信息。Algorithm 如何在完全二叉树的最后一级找到最右节点的位置?,algorithm,binary-tree,Algorithm,Binary Tree,我在二叉树中做一个问题,当我遇到一个问题,在一个完整的二叉树的最后一级找到最右边的节点,这里的问题是我们必须在O(n)时间内完成它,这是一个停止点,在O(n)中完成它很简单,通过遍历所有元素,但是有没有一种方法可以在小于O(n)的复杂度下完成这项工作,我在网上浏览了很多次,但我找不到关于这件事的任何信息。 提前感谢。因为它是一个完整的二叉树,所以遍历所有正确的节点,直到到达叶子为止,将取O(logN),而不是O(N)。在常规二叉树中需要O(N),因为在最坏的情况下,所有节点都排列在右侧,但由于它
提前感谢。因为它是一个完整的二叉树,所以遍历所有正确的节点,直到到达叶子为止,将取O(logN),而不是O(N)。在常规二叉树中需要O(N),因为在最坏的情况下,所有节点都排列在右侧,但由于它是一个完整的二叉树,它不可能是是的,您可以在
O(log(N)^2)
中通过执行二进制搜索的变体来完成
这可以通过先到最左边的元素1,然后到第二个最左边的元素,然后到第四个最左边的元素,第八,。。。直到你发现没有这样的元素。
假设您找到的最后一个元素是i
th,第一个未找到的元素是2i
现在,您只需在该范围内进行二进制搜索
这是O(log(n/2))=O(logn)
总迭代次数,由于每次迭代都沿着整棵树进行,所以它是O(log(n)^2)
时间的总和
(1) 在这里和下面的内容中,“x最左边的元素”仅指树最深处的节点。我假设您知道节点的数量。让
n
这样的数字
在一个完整的二叉树中,级别i
的节点数是级别i-1
的两倍
因此,您可以在2
之间迭代划分n
。如果有剩余项,则n
是正确的子项;否则,他就是一个左撇子。无论是否有余数,都要存储到序列中,最好是堆栈中
例如:
Stack<char> s;
while (n > 1)
{
if (n % 2 == 0)
s.push('L');
else
s.push('R');
n = n/2; // n would int so division is floor
}
stacks;
而(n>1)
{
如果(n%2==0)
s、 推动('L');
其他的
s、 推动('R');
n=n/2;//n将为int,因此除法为floor
}
当while
完成时,堆栈包含指向最右侧节点的路径
执行
时执行的次数为log_2(n)
这是具有时间复杂度O(lg n*lg n)和空间复杂度O(lg n)(考虑堆栈存储空间)的递归解决方案
使用下面代码的迭代版本,可以将空间复杂度降低到O(1)
// helper function
int getLeftHeight(TreeNode * node) {
int c = 0;
while (node) {
c++;
node = node -> left;
}
return c;
}
int getRightMostElement(TreeNode * node) {
int h = getLeftHeight(node);
// base case will reach when RightMostElement which is our ans is found
if (h == 1)
return node -> val;
// ans lies in rightsubtree
else if ((h - 1) == getLeftHeight(node -> right))
return getRightMostElement(node -> right);
// ans lies in left subtree
else getRightMostElement(node -> left);
}
时间复杂度推导-
在每个递归步骤中,我们考虑左子树或右子树,即最大高度(lgn)函数调用的n/2个元素,
计算高度需要花费lgn时间-
T(n) = T(n/2) + c1 lgn
= T(n/4) + c1 lgn + c2 (lgn - 1)
= ...
= T(1) + c [lgn + (lgn-1) + (lgn-2) + ... + 1]
= O(lgn*lgn)
想想托马斯,我是说它会访问所有节点,我是在要求一个更好的方法,就像amit说的那样,如果你保存(并保持同步)树中的总节点数,那么它是O(logN),因为你知道什么时候访问左分支或右分支。将它添加到堆栈本身会导致O(n)时间,所以这一次并不重要,不是阿斯温·梅西利。插入堆栈是O(1)。请注意,还可以使用列表或向量。时间与插入次数绑定,即log_2(n)