我使用DFS并递归编码此问题,如下所示:
/**
* recursive
*/
public static List<List<Integer>> printAllPath(TreeNode root) {
List<List<Integer>> rst = new ArrayList<List<Integer>>();
helper(rst, new ArrayList<Integer>(), root);
return rst;
}
public static void helper(List<List<Integer>> rst, ArrayList<Integer> list,
TreeNode root) {
if (root == null) {
return;
}
list.add(root.val);
if (root.left == null && root.right == null) {
rst.add(new ArrayList<Integer>(list));
}
helper(rst, list, root.left);
helper(rst, list, root.right);
list.remove(list.size() - 1);
}
在搜索互联网后,我发现此算法的平均时间复杂度为O(nlogn)
,最差的情况为O(n^2)
,这是正确的吗?为什么?有人可以解释一下吗?
我不太熟悉分析树的时间复杂度。在这个问题中,如果我使用Queue
来实现,时间复杂度应该是O(n)
对吗?因为我只是迭代整个树一次。
但是如何分析使用递归的树的时间复杂度。?
答案 0 :(得分:3)
您的代码显然会收集并返回从根节点到叶节点的所有路径。它通过使用DFS实现。在算法执行期间访问每个节点,并且不会多次访问它们。但是,您必须在找到路径时打印或存储路径。在您的计划中,您创建新的ArrayList
并将其存储在变量rst
中。路径数等于叶节点数l
,路径长度等于树h
的高度,因此总复杂度为O(n + hl)
。
l
和h
的值不是独立的,因此我们来看两个有趣的案例。在平衡二叉树的情况下,平均有n/2
个叶节点,高度为log2(n)
,这给出O(nlogn)
。另一方面,当树在链表中退化时,只有一个叶子,并且该路径的长度为n
,因此这种情况的复杂度为O(n)
。
但是如何分析使用树的时间复杂度 递归?
关于时间复杂度,只计算递归调用的数量。如果空间复杂性是个问题,请通过迭代替换递归。
另见:
答案 1 :(得分:0)
当构建根到叶路径时,树中的每个节点都被触摸一次,因此它的复杂度为O(N)
,其中N
是树中节点的数量,如上所述。
但是当将根到叶的路径添加到结果列表中时
(在代码段中rst.add(new ArrayList<Integer>(list));
),然后复制包含路径的整个数组。由于数组副本的复杂性与其长度呈线性关系,而表示根到叶路径的数组大致包含h
个节点,其中h
是树的高度,而不是整体O(N * h)
复杂性。
例如,考虑完美的二叉树。它具有N / 2
叶节点,因此每个N / 2
长度为log N
的{{1}}根路径路径。迭代这些路径 - 直接复制或打印 - 总共涉及log N * N / 2
,相当于O(N * h)
。