我正在经历Maximum Binary Tree leetcode问题。 TL; DR是您有一个数组,例如:
[3,2,1,6,0,5]
您应该采用最大元素并使其成为树的根。然后将数组拆分为该元素左侧的部分和其右侧的部分,它们分别用于以相同的方式递归创建左侧和右侧子树。
LeetCode声称,最佳解决方案(在“解决方案”选项卡中显示)在每个递归步骤中均使用线性搜索子数组的最大值。在最坏的情况下,这是O(n ^ 2)。这是我想出的解决方案,很简单。
但是,我正在浏览其他提交的内容,找到了线性时间解决方案,但是我一直在努力了解其工作原理!看起来像这样:
def constructMaximumBinaryTree(nums):
nodes=[]
for num in nums:
node = TreeNode(num)
while nodes and num>nodes[-1].val:
node.left = nodes.pop()
if nodes:
nodes[-1].right = node
nodes.append(node)
return nodes[0]
我已经分析了此函数,总的来说,这似乎是线性时间(O(n)),因为每个唯一节点最多只能添加到nodes
数组中或从中弹出。我尝试使用不同的示例输入来运行它,但我一直在努力将各个点连接起来,并全神贯注于其工作原理。有人可以给我解释一下吗?
答案 0 :(得分:0)
理解算法的一种方法是考虑循环不变性。在这种情况下,nodes
的数组始终满足以下条件:每次执行for-loop
之前和之后:
nodes
为空,并且最大二叉树不存在(例如,如果输入nums
为空)nodes
中的第一项是最大二叉树,它基于从输入nums
到现在为止已处理的数据 while-loop
确保当前最大二叉树是nodes
数组中的第一项,否则,它将被弹出并添加为left
子树。
在for-loop
的每次迭代中,检查:
if nodes:
nodes[-1].right = node
将当前节点作为右子树添加到nodes
数组的最后一项。并且,当发生这种情况时,当前节点小于nodes
数组中的最后一个节点(因为每个输入整数都被定义为唯一)。并且由于当前节点小于数组中的最后一个节点,因此最后一个节点充当一个分区点,其值大于当前项目,这就是为什么将当前节点添加为右子树的原因。
nodes
数组中有多个项目时,每个项目都是该项目左侧的子树。
对于运行时间,让 n 为输入nums
的长度。 for循环有 n 个执行。如果输入数据按降序排序,但最大输入值位于输入末尾(例如:4、3、2、1、5),则在每次迭代期间将跳过内部while循环,直到最后一个for循环迭代。在最后一个for循环迭代中,while循环将运行 n-1 次,总运行时间为 n +(n-1) => 2n-1 => O(n)。