我在面试时被问到这个问题。这是我的O(log n)
解决方案。
查找节点的深度。
重复搜索,但请停在depth - n
。
如果没有第二次通过,有没有办法做到这一点?
答案 0 :(得分:3)
在搜索节点时,您可以跟踪从当前节点到根节点的路径中的所有节点。这是一个长度不大于树深度的简单列表。找到节点后,其 n 的祖先位于列表中 length - n 的位置。
答案 1 :(得分:1)
只需查找节点并按照后面的步骤保存路径。大致这个(对于一颗彗星树):
Node* nthAncestor(Node* root, int target, int n)
{
Node* list[n];
int pos = 0;
Node* node = root;
while(node->value != target)
{
list[pos] = node;
pos = (pos + 1) % n;
if(node->value < target)
node = node->left;
else if(node->value > target)
node = node->right;
}
return list[(pos + 1) % n];
}
请注意我假设第n个祖先 存在。
对于大小为T的树,它会在O(log T)
时间内运行并使用O(n)
空格( n ,如 n 祖先)。< / p>
答案 2 :(得分:1)
我猜你的问题有点不对劲。你错过了一件重要的事情。当然你可以在没有第二次通过的情况下完成。只需在搜索中保留最后n个节点的queue。
您错过的是这种算法需要O(log n)
内存。虽然您的解决方案会消耗内存使用的时间消耗,并使用O(1)
(常量)额外内存)
所以你的解决方案不是“错误”或“太慢”。它只是有自己的优点和缺点。
答案 3 :(得分:1)
嗯,在我看来,只需要一个额外节点或更少空间的简单方法就是拥有一个保持回溯计数的虚拟节点。当您找到搜索目标时,然后将虚拟节点设置为 n 并返回 it ,而不是您找到的您不想要的节点。
您需要一个仅为虚拟节点返回true的函数DUMMY(node)
。 (DUMMY()
可以通过比较节点地址或通过检查节点内的魔术cookie来实现。)
Node *search(Node *next) {
if (found the the answer)
dummy->backtrack = n;
return dummy;
} else r = search(whatever ? n->left : n->right);
if (DUMMY(r)) {
if (dummy->backtrack == 0)
return next;
--dummy->backtrack;
}
return r;
}
答案 4 :(得分:1)
为此使用n间隔队列。每当你找到一个,出列队列并入队时,
findnth(node *root, queue q, int n, int number)
{
if(!root || !q)
return;
findnth(root->left, q, n, number);
if(root->d == number) {
if(q.size() < n) {
nth ancestor not exist;
print q->deq() as q.size() ance return;
}
else
print q.deq()
}
if(q.size() < n) {
q.ins(node->data);
}
else {
q.deq();q.enq(node->data);
}
findnth(root->right, q, n, number);
}
答案 5 :(得分:0)
是的,可以在没有第二遍的情况下完成。你只需要使用两个指针。这是你如何做到的
答案 6 :(得分:0)
I think this function might help ...
function printAncestor(node *root , node *search , int *k)
{
if(!root)
return 0;
if(root == search)
return 1;
int p1 ,p2;
p1 = printAncestor(root->left , search , k);
p2 = printAncestor(root->right , search , k);
if(p1) {
(*k)--;
if(*k >0)
printf("%d ",root->left->value);
return 1;
}
if(p2)
{
(*k)--;
if(*k >0)
printf("%d ",root->right->value);
return 1;
}
}
这背后的逻辑是,我们直到搜索节点从根通过递归。当我们找到它时,我们沿着它来自的路径遍历并打印它。