给定一个BST,是否有可能找到两个加起来给定值的数字,在O(n)时间和额外的内存很少。通过少量额外内存,暗示您无法将整个BST复制到数组中。
答案 0 :(得分:4)
如果你有子指针和父指针,这可以在O(n)时间和O(1)额外内存中完成。保留两个指针x和y,并在最小元素处开始x,在最大元素处开始y。如果这两个元素的总和太低,则将x移动到其后继,如果它太高则将y移动到其前一个元素。一旦x指向比y更大的元素,就可以报告失败。对于总共O(n)个边缘遍历,树中的每个边最多遍历两次,并且您唯一的内存使用是两个指针。如果没有父指针,你需要记住根的祖先序列,至少是Omega(log n),如果树是不平衡的,可能更高。
要查找后继者,您可以使用以下伪代码(前一代表的类似代码):
succ(x) {
if (x.right != null) {
ret = x.right;
while (ret.left != null) ret = ret.left;
return ret;
} else {
retc = x;
while (retc.parent != null && retc.parent < x) retc = retc.parent;
if (retc.parent != null && retc.parent > x) return retc.parent;
else return null;
}
}
答案 1 :(得分:2)
我认为jonderry非常接近,但是父指针需要\ Omega(n)内存,即它们大大增加了内存使用量。他正在做的是在相反的方向上进行两次协调遍历(从小到大和viveversa),试图保持总和始终接近目标,你可以用两个堆栈来管理它,并且堆栈只能长到树的深度那就是O(log n)。我不知道这是否是“小”的额外内存,但肯定是额外的内存和o(n)。所以这与jonderry自己的注释完全一样,但是没有运行时惩罚,因为仅使用堆栈遍历二叉树是众所周知且高效且绝对是O(n)操作。所以你有增加迭代器ii和减少迭代器di。
x = ii.next()
y = di.next()
while (true) {
try:
if x + y > target {y = di.next()}
if x + y < target {x = ii.next()}
if x + y == target {return (x,y)}
except IterError:
break
}
return None
我在计算假媒体的上下文中遇到了同样的问题,即样本中所有成对平均值的中位数。
答案 2 :(得分:-1)
是的,如果你解析它,因为它将是一个排序数组。