是的,这两者都可以在一次通过中实现。
首先,预购级别,因为这更容易一些。由于这是一个水平填充树,对于数组中的任何节点,给定它的索引i,左子树节点的索引公式为2*i+1,右为2*i+2。因此,我们以预先顺序递归调用它们,将根节点附加到所需数组的后面。
def level_to_pre(arr,ind,new_arr):
if ind>=len(arr): return new_arr #nodes at ind don't exist
new_arr.append(arr[ind]) #append to back of the array
new_arr = level_to_pre(arr,ind*2+1,new_arr) #recursive call to left
new_arr = level_to_pre(arr,ind*2+2,new_arr) #recursive call to right
return new_arr
然后这样调用,这里将填充最后一个空白数组。
ans = level_to_pre([1,2,3,4,5,6],0,[])
现在在我进入 pre to level 部分之前,请记住 dfs 使用递归,它在后台使用堆栈。 bfs 使用队列的地方。而我们手中的问题,以层优先顺序填充数组,基本上是 bfs。因此,我们将不得不显式维护一个队列来模拟这些递归调用,而不是递归调用(即堆栈)。
我们在这里所做的是,给定子树的根,我们首先将它添加到答案数组。现在,与上面的问题不同,查找子节点的索引具有挑战性。左边的很简单,root之后就可以了。为了找到右索引,我们计算左子树的总大小。这是可能的,因为我们知道它是水平填充的。我们现在使用一个辅助函数left_tree_size(n),它返回给定整个树的大小的左子树的大小。因此,除了根的索引之外,在递归的情况下我们将传递的第二个参数是这个子树的大小。为了反映这一点,我们在队列中放置了一个 (root,size) 元组。
from math import log2
import queue
def pre_to_level(arr):
que = queue.Queue()
que.put((0,len(arr)))
ans = [] #this will be answer
while not que.empty():
iroot,size = que.get() #index of root and size of subtree
if iroot>=len(arr) or size==0: continue ##nodes at iroot don't exist
else : ans.append(arr[iroot]) #append to back of output array
sz_of_left = left_tree_size(size)
que.put((iroot+1,sz_of_left)) #insert left sub-tree info to que
que.put((iroot+1+sz_of_left,size-sz_of_left-1)) #right sub-tree info
return ans
最后,这里是辅助函数,通过几个例子来弄清楚它为什么起作用。
def left_tree_size(n):
if n<=1: return 0
l = int(log2(n+1)) #l = no of completely filled levels
ans = 2**(l-1)
last_level_nodes = min(n-2**l+1,ans)
return ans + last_level_nodes -1