您获得了数字BST。你必须在其中找到两个数字(a,b),使得a + b = S
,在O(n)时间和O(1)空间中。
算法可能是什么?
一种可能的方法是两个将BST转换为双向链接列表,然后从前端和尾端开始:
if front + end > S then end--
或者:
if front + end < S then front++
答案 0 :(得分:4)
我最近在一次采访中被问到了这个问题。当我被困住时,我得到了一个暗示。
提示:假设您需要为排序数组解决同样的问题,那么您将如何解决它。
我:保持两个指针。一个在开头,另一个在最后。如果这些指针的元素总和小于所需的总和,则将前指针向右移动,否则将后指针向左移动。
采访者:你怎么能对二元搜索树做同样的事情?Me:执行有序遍历,并将指针保存到数组中的节点。并使用与数组相同的逻辑。
采访者:是的,这很有效。但是空间复杂度是O(n)。你能减少它吗?我(经过很长时间):好的,使用this算法将BST转换为双向链表。然后使用与数组相同的逻辑。由于递归,空间复杂度将为O(lg(n))。
答案 1 :(得分:3)
尽我所能,我不确定这是否可能使用没有父指针的二叉树。 O(1)
空格意味着既不能使用递归(堆栈增长为O(log n)
)也不能复制到双向链表(O(n)
)。
您提到的方法是 O(n)
时间复杂度解决方案,但不是普通的二叉树。事实上,我非常详细地回答了类似的问题here。这是用O(n)
空格解决的,但仅仅因为它们最初没有排序。
使用包含父指针的树可以 。如果子节点有指向父节点的指针,则基本上可以将树视为迭代处理的双向链表。
为此,您将开始指针向下运行到最左侧节点,将结束指针向下运行到最右侧节点。您还维护两个变量来存储每个指针的最后一个移动(向上或向上,最初向上),这样您就可以智能地选择下一个移动(问题中的front++
和end--
)。
然后你可以使用当前指针和最后一个动作以及当前总和来决定要移动的指针(以及如何移动)。
答案 2 :(得分:3)
正如其他人所提到的,你无法在恒定的O(1)空间中解决这个问题。此外,当前建议的所有其他解决方案至少使用O(log ^ 2 n)空间,而不是O(log n)空间:堆栈具有O(log n)帧,并且每个帧具有O(log n)大小的指针。
现在,@ dharm0us目前接受的解决方案通过将BST转换为数组来破坏BST。这是不必要的。相反,使用两个迭代器,一个执行有序遍历,一个执行反向遍历,并查找两个与数组中相同的数字。每个迭代器都有一个带有O(log n)帧的堆栈,每个帧保存一个O(log n)大小指针,用于总空间O(log ^ 2 n)。时间显然是线性的O(n)。