我得到了一棵树T
,其中有n
个节点和l
个树叶。
我必须选择一些包含k (<=l)
叶子的子树。如果我选择节点t
的祖先子树,我们就无法选择t
的子树。
例如:
这是树T
,它有13个节点(7个叶子)。
如果我想选择k = 4
叶子,我可以选择节点4和6(或节点2和5)。这是选择的最小数量。 (我们也可以选择节点6,7,8,9,但这不是最小值。)
如果我想选择k = 5
叶子,我可以选择节点3,这是选择的最小数量。
我想选择最小数量的子树。我只能找到O(nk^2)
和O(nk)
算法,它使用BFS和动态编程。选择这个有更好的解决方案吗?
谢谢:)
答案 0 :(得分:2)
实际上,要了解每个子树的叶子数量,您只需要通过每个节点一次,因此复杂度应为O(nm)
,其中m
是平均值每个节点的子节点,在大多数情况下计算为O(n)
,因为m
只是一个常量。要做到这一点,你应该:
您可以通过从叶子开始并将父项放入队列来完成此操作。当您从队列中弹出节点n_i
时,将每个子树中包含的叶子数从每个n_i
的子节点开始求和。完成后,将n_i
标记为已访问(因此您不会多次访问它,因为每个孩子可以添加一次)
这就是这样的:
^
| f (3) This node last
| / \
| / \
| / \
| / \
| d (2) e (1) These nodes second
| / \ /
| / \ /
| a (1) b (1) c (1) These nodes first
步骤如下:
Find leaves `a`, `b` and `c`.
For each leave, add parent to queue # queue q = (d, d, e)
Pop d # queue q = (d, e)
Count leaves in subtree: d.leaves = a.leaves + b.leaves
Mark d as visited
Add parent to queue # queue q = (d, e, f)
Pop d # queue q = (e, f)
d is visited, do nothing
Pop e # queue q = (f)
Count leaves in subtree: e.leaves = c.leaves
Mark d as visited
Add parent to tree # queue q = (f, f)
Pop f # queue q = (f)
Count leaves in subtree: f.leaves = d.leaves + e.leaves
Mark d as visited
Add parent to tree (none)
Pop f # queue q = ()
f is visited, do nothing
您还可以使用智能数据结构来忽略添加两次的节点。请注意,您不能使用有序集,因为在“较高”节点之前探索“较低”节点非常重要。
在您的情况下,如果队列中的节点具有超过k
个叶子,则可以消除队列中的节点,并返回找到的具有k
个叶子的每个节点,这将提供更快的算法。