Google – Generate All Full Trees with N Leaves / h Height
n leaves的full tree有多少种可能性? 输出所有full tree?
h heights的full tree有多少种可能性? 输出所有full tree?
[Analysis]
(1) a什么是full tree?
Full tree是一种binary tree, 其中每个node,要么没有children,要么就有两个children。
(2) Full tree和Complete tree的区别?
Complete tree除了最后一层,其他层都必须是满的,而full tree没有这种规定。
另外Complete tree可以出现只有一个child的情况,而full tree不允许。
(3) Full tree有哪些特点?
如果full tree有n个leaves,那么total number of nodes = 2 * n – 1.
(4) 怎么证明?
简单的方法:
可以想象成一个1 v 1的game, 比到最后只会有一个大赢家,那么就会有 n – 1个internal node, 因为除了最后的赢家,其他每个玩家只会输一次且仅有一次。
严格的方法:
数学归纳法,假设n – 1个leaves成立,有2 * (n – 1) – 1 = 2 * n – 3个nodes。如果要新增加一个leaf,因为full tree的特性,必须加入两个children到其中一个leaf上,这样leaves减一加二就等于n,那么总共的node数量就+2, 2 * n – 3 + 2 = 2 * n – 1.
[Solution]
[#1 Solution]
方法类似于leetcode的unique binary tree,对于root来说,如果left subtree包含k个leaves, 那么right subtree就必须包含n – k个leaves. 无需考虑奇偶的情况,因为奇数leaves也一样能组成一棵full tree.
固定height的做法有点难,因为对于root来说,只需要left subtree或者right subtree其中之一的height为h – 1就可以了。比如left subtree的height为h – 1,那么对于right subtree,它的高度可以是[1, h – 1]之间的任何一个值。另外对于root,left和right subtree属于对称的情况。
第二题的code有一点要特别注意,因为left subtree和right subtree是属于对称情况,一开始直接两种对称情况一起加入到leftSub和rightSub的lists里面,再通过两层for循环建当前的tree。
但是这样会出现bug,比如高度为1的left subtree会和高度也为1的right subtree组成新的tree。这样是不对的,高度为1的left subtree只能和高度为h – 1的right subtree组成新tree。
还有一点optimization是写这篇Post的时候才想到的,Solution2里面第57和第71两行可以放到for loop外面,可以省掉不少递归。(因为这两行递归h – 1,递归里还有n多递归呢)。
Read full article from Google – Generate All Full Trees with N Leaves / h Height
n leaves的full tree有多少种可能性? 输出所有full tree?
h heights的full tree有多少种可能性? 输出所有full tree?
[Analysis]
(1) a什么是full tree?
Full tree是一种binary tree, 其中每个node,要么没有children,要么就有两个children。
(2) Full tree和Complete tree的区别?
Complete tree除了最后一层,其他层都必须是满的,而full tree没有这种规定。
另外Complete tree可以出现只有一个child的情况,而full tree不允许。
(3) Full tree有哪些特点?
如果full tree有n个leaves,那么total number of nodes = 2 * n – 1.
(4) 怎么证明?
简单的方法:
可以想象成一个1 v 1的game, 比到最后只会有一个大赢家,那么就会有 n – 1个internal node, 因为除了最后的赢家,其他每个玩家只会输一次且仅有一次。
严格的方法:
数学归纳法,假设n – 1个leaves成立,有2 * (n – 1) – 1 = 2 * n – 3个nodes。如果要新增加一个leaf,因为full tree的特性,必须加入两个children到其中一个leaf上,这样leaves减一加二就等于n,那么总共的node数量就+2, 2 * n – 3 + 2 = 2 * n – 1.
[Solution]
[#1 Solution]
方法类似于leetcode的unique binary tree,对于root来说,如果left subtree包含k个leaves, 那么right subtree就必须包含n – k个leaves. 无需考虑奇偶的情况,因为奇数leaves也一样能组成一棵full tree.
T(n) = T(k) + T(n – k), k ∈ [1, n – 1][#2 Solution]
固定height的做法有点难,因为对于root来说,只需要left subtree或者right subtree其中之一的height为h – 1就可以了。比如left subtree的height为h – 1,那么对于right subtree,它的高度可以是[1, h – 1]之间的任何一个值。另外对于root,left和right subtree属于对称的情况。
T(n) = 2 * T(n – 1) * (T(1) + T(2) + … + T(n – 1)) – T(n – 1) * T(n – 1)[Note]
left/right subtree 高度都为h – 1的情况算了两次,所以要减掉一次。
第二题的code有一点要特别注意,因为left subtree和right subtree是属于对称情况,一开始直接两种对称情况一起加入到leftSub和rightSub的lists里面,再通过两层for循环建当前的tree。
但是这样会出现bug,比如高度为1的left subtree会和高度也为1的right subtree组成新的tree。这样是不对的,高度为1的left subtree只能和高度为h – 1的right subtree组成新tree。
还有一点optimization是写这篇Post的时候才想到的,Solution2里面第57和第71两行可以放到for loop外面,可以省掉不少递归。(因为这两行递归h – 1,递归里还有n多递归呢)。
Code是输出所有full tree,计算数量可以通过上面递推式求得。
// n leaf nodesclass Solution { public List<TreeNode> allFullTrees(int n) { List<TreeNode> result = new ArrayList<>(); if (n == 0) { return result; } if (n == 1) { result.add(new TreeNode(1)); return result; } for (int i = 1; i < n; i++) { List<TreeNode> leftSub = allFullTrees(i); List<TreeNode> rightSub = allFullTrees(n - i); for (TreeNode l : leftSub) { for (TreeNode r : rightSub) { TreeNode root = new TreeNode(1); root.left = l; root.right = r; result.add(root); } } } return result; }}// h height// T(n) = 2 * T(n - 1) * (T(1) + T(2) + ... + T(n - 1)) - T(n - 1) * T(n - 1)class Solution2{ public List<TreeNode> allFullTrees(int h) { List<TreeNode> result = new ArrayList<>(); if (h == 0) { return result; } buildTree(h, result); return result; } private void buildTree(int h, List<TreeNode> result) { if (h == 0) { return; } if (h == 1) { result.add(new TreeNode(1)); return; } List<TreeNode> leftSub = new ArrayList<>(); List<TreeNode> rightSub = new ArrayList<>(); for (int i = 1; i < h; i++) { buildTree(i, leftSub); buildTree(h - 1, rightSub); for (TreeNode l : leftSub) { for (TreeNode r : rightSub) { TreeNode root = new TreeNode(1); root.left = l; root.right = r; result.add(root); } } leftSub.clear(); rightSub.clear(); if (i != h - 1) { buildTree(i, rightSub); buildTree(h - 1, leftSub); for (TreeNode l : leftSub) { for (TreeNode r : rightSub) { TreeNode root = new TreeNode(1); root.left = l; root.right = r; result.add(root); } } leftSub.clear(); rightSub.clear(); } } }}