我将一个完整的子树定义为一个树,其中所有级别都已满,最后一级左对齐,即所有节点都尽可能地离开,我希望在树中找到最大的完整子树。
一种方法是以root身份为每个节点执行概述here的方法,这将花费O(n ^ 2)时间。
有更好的方法吗?
答案 0 :(得分:4)
由于上面没有C ++解决方案,我已经添加了我的解决方案。如果您觉得有任何不正确或有任何改进可以告诉我。
struct CompleteStatusWithHeight {
bool isComplete;
int height;
};
int FindLargestCompletetSubTreeSize(const unique_ptr<BinaryTreeNode<int>>& tree)
{
return CheckComplete(tree).height;
}
CompleteStatusWithHeight CheckComplete(const unique_ptr<BinaryTreeNode<int>>& tree)
{
if (tree == nullptr) {
return {true, -1}; // Base case.
}
auto left_result = CheckComplete(tree->left);
if (!left_result.isComplete) {
return {false, 0}; // Left subtree is not balanced.
}
auto right_result = CheckComplete(tree->right);
if (!right_result.isComplete) {
return {false, 0}; // Right subtree is not balanced.
}
bool is_balanced = abs(left_result.height - right_result.height) == 0;
bool is_left_aligned = (left_result.height - right_result.height) == 1;
bool is_leaf = left_result.height == -1 && right_result.height ==-1;
bool is_complete = is_balanced || is_left_aligned || is_leaf;
int height = max(left_result.height, right_result.height) + 1;
return {is_complete, height};
}
答案 1 :(得分:3)
这是我在Python中的解决方案。它正在处理我提出的案件。 返回值的含义如下: [X,Y,Z]
z:0 - 完整子树,1 - 只有一个节点在这个子树中有一个左子节点,2 - 不是一个完整的子树
def largest_complete_tree(root):
result = traverse_complete(root)
print('largest complete subtree: {}'.format(result[0]))
def traverse_complete(root):
if root:
left = traverse_complete(root.left)
right = traverse_complete(root.right)
max_complete = max(left[0], right[0])
max_height = max(left[1], right[1])
left_child_only = 1 if (left[2] == 1 and right[0] == 0) or (left[0] == 1 and right[0] == 0) else 0
# 5 conditions need to pass before left and right can be joined by this node
# to create a complete subtree.
if left[0] < right[0]:
return [max_complete, 0, 2]
if left[2] == 2 or right[2] == 2:
return [max_complete, 0, 2]
if abs(left[1]-right[1]) > 1:
return [max_complete, 0, 2]
if (left[2] == 1 and right[2] == 1) or (left[2] == 0 and right[2] == 1):
return [max_complete, 0, 2]
if left[0] == right[0] and left[0] != 2**left[0] - 1:
return [max_complete, 0, 2]
return [left[0] + right[0] + 1, max_height + 1, left_child_only]
else:
return [0,0,0]
答案 2 :(得分:2)
定义树节点的等级,如果此节点为root,则为最大完整子树的高度。
如果此节点为root,则将节点宽度定义为最大完整子树的最后一级中的节点数。
因此,对于树中的每个节点,我们有两个数字(r, w)
。并w <= 2^r
。
如果节点为零或只有一个子节点,则节点具有(r, w) = (1, 1)
。
如果节点有两个孩子(r1, w1)
和(r2, w2)
,我们会遇到以下几种情况:
r1 > r2
时,(r2 + 1, 2^r2 + w2)
当节点有r1 == r2
w1 == 2^r1
和(r1 + 1, w1 + w2)
当节点有r1 == r2
时,w1 < 2^r1
和(r1 + 1, w1)
示例:
root
....
/ \ / \
l l r r
/\ / /\ /
l l l r r r
最大完整子树
m
....
/ \ / \
m m m m
/\ / /\ /
m m m r r r
r1 < r2
时,w1 == 2^r1
和(r1 + 1, 2 * w1)
示例:
root
....
/ \ / \
l l r r
/\ / \ /\ /\
l l l l r r r r
/
r
最大完整子树
m
....
/ \ / \
m m m m
/\ / \ /\ /\
m m m m m m m m
/
r
r1 < r2
时,w1 < 2^r1
和(r1 + 1, w1)
醇>
示例:
root
....
/ \ / \
l l r r
/\ / /\ /\
l l l r r r r
/
r
最大完整子树
m
....
/ \ / \
m m m m
/\ / /\ /\
m m m r r r r
/
r
根据此规则,您可以使用递归计算每个节点的(r, w)
。它需要O(n)
。当您在此节点中找到具有最大等级r
的节点时,查找具有最大w
的节点,并且此节点应该是一个解决方案。
答案 3 :(得分:2)
我正在编写一个“编程访谈元素”的变体时遇到过这篇文章。我想分享我的想法和代码。
欢迎任何评论。
我正在使用递归来解决这个问题。 max用于存储有史以来发生的最大大小(我使用了一个数组,因为java是按值计算的)。 返回值信息包含有关树的信息 传入的是一棵完整的树。仅在完成时返回树大小,否则返回(-1,false)。 如果一个子树T&#39;如果不完整,则永远不会选择其大小来组成更大的完整树。并且所有T子树的大小总是以最大值记录,所以我们永远不会错过任何值。
以下是它的工作原理
根据左/右子的返回值处理当前树 - leftInfo和rightInfo。
如果两者都不完整,则树不完整,无需更新 最大。如果其中任何一个完成,则表示树未完成,请将max更新为 左右两侧的尺寸越大。如果两者都完整,那么树 可能是完整的。首先检查左边是否完美,然后 正确满足高度要求。如果是,那么回来(真的, 新尺寸)。否则,树不完整,更新max为 更大的左右价值。
下面是我的代码。它应该是时间O(n)和空间O(h),其中h是树的高度。(如果它是平衡的,否则最坏的情况将是O(n))。< / p>
public class Solution {
public static void main(String[] args){
TreeNode[] trees = new TreeNode[10];
for(int i = 0; i < 10; i++){
trees[i].val = i;
}
}
public int largestCompleteTree(TreeNode root){
int[] max = new int[1];
helper(root, max);
return max[0];
}
private Info helper(TreeNode root, int[] max){
//Base case:
if(root == null){
return new Info(0, true);
}
if(root.left == null && root.right == null){
max[0] = Math.max(max[0], 1);
return new Info(1, true);
}
//Recursion
Info leftInfo = helper(root.left, max);
Info rightInfo = helper(root.right, max);
//Process based on left subtree and right subtree.
//Neither is complete.
if(!leftInfo.isComplete && !rightInfo.isComplete){
//Do not need to update the max value.
return new Info(-1, false);
}
//One of the subtree is complete, the current tree is not complete
else if(!leftInfo.isComplete || !rightInfo.isComplete){
if(leftInfo.isComplete){
max[0] = Math.max(max[0], leftInfo.size);
return new Info(-1, false);//the value has been recorded
}else{
max[0] = Math.max(max[0], rightInfo.size);
return new Info(-1, false);
}
}
//Both subtrees are complete,
else{
int size = 0;
if(((rightInfo.size & (rightInfo.size + 1)) == 0 &&
leftInfo.size >= rightInfo.size &&
leftInfo.size <= rightInfo.size*2 + 1)||
((leftInfo.size & (leftInfo.size + 1)) == 0 &&
rightInfo.size >= (leftInfo.size - 1)/2 &&
rightInfo.size <= leftInfo.size))
{
size = leftInfo.size + rightInfo.size + 1;
max[0] = Math.max(max[0], size);
return new Info(size, true);
}
else{ //find the subtree with the greater size
size = leftInfo.size > rightInfo.size ? leftInfo.size : rightInfo.size;
max[0] = Math.max(max[0], size);
return new Info(0, false);
}
}
}
class Info {
boolean isComplete;
int size;
public Info(int size, boolean isComplete){
this.isComplete = isComplete;
this.size = size;
}
}
}
答案 4 :(得分:1)
在“编程访谈元素”一书中遇到了这个任务,似乎我发现了一个非常简单的解决方案,但仍然不确定它是否正确,但在几个案例中进行了测试并且它有效:
private struct str
{
public bool isComplete;
public int height, size;
public str(bool isComplete, int height, int size)
{
this.isComplete = isComplete;
this.height = height;
this.size = size;
}
}
public int SizeOfLargestComplete()
{
return SizeOfLargestComplete(root).size;
}
private str SizeOfLargestComplete(Node n)
{
if (n == null)
return new str(true, -1, 0);
str l = SizeOfLargestComplete(n.left);
str r = SizeOfLargestComplete(n.right);
if (!l.isComplete || !r.isComplete)
return new str(false, 0, Math.Max(l.size, r.size));
int numberOfLeftTreeLeafes;
if (l.height == -1)
numberOfLeftTreeLeafes = 0;
else
numberOfLeftTreeLeafes = l.size - ((1 << l.height) - 1);
bool leftTreeIsPerfect = (1 << (l.height + 1)) - 1 - l.size == 0;
//if left subtree is perfect, right subtree can have leaves on last level
if (leftTreeIsPerfect)
if (l.size - r.size >= 0 && l.size - r.size <= numberOfLeftTreeLeafes)
return new str(true, l.height + 1, l.size + r.size + 1);
else
return new str(false, 0, Math.Max(l.size, r.size));
//if left subtree is not perfect, right subtree can't have leaves on last level
//so size of right subtree must be the same as left without leaves
else
if (r.size == l.size - numberOfLeftTreeLeafes)
return new str(true, l.height + 1, l.size + r.size + 1);
else
return new str(false, 0, Math.Max(l.size, r.size));
}
答案 5 :(得分:0)
我找到了一个类似于上面的米哈伊尔的解决方案(当我通过EPI书时遇到)。我已经对完整的树,一棵完美的树,一棵完整的树以及完整树的树木进行了几次排列测试,但并非详尽无遗。
/**
* Returns the largest complete subtree of a binary tree given by the input node
*
* @param root the root of the tree
*/
public int getLargestCompleteSubtree(INode<TKeyType, TValueType> root) {
max = 0;
calculateLargestCompleteSubtree(root);
return max;
}
/**
* Returns the largest complete subtree of a binary tree given by the input node
*
* @param root the root of the tree
*/
public TreeInfo<TKeyType, TValueType> calculateLargestCompleteSubtree(INode<TKeyType, TValueType> root) {
int size = 0;
// a complete subtree must have the following attributes
// 1. All leaves must be within 1 of each other.
// 2. All leaves must be as far left as possible, i.e, L(child).count() > R(child).count()
// 3. A complete subtree may have only one node (L child) or two nodes (L, R).
if (root == null)
{
return new TreeInfo<>(true, 0);
}
else if (!root.hasLeftChild() && !root.hasRightChild())
{
return new TreeInfo<>(true, 1);
}
// have children
TreeInfo<TKeyType, TValueType> leftInfo = calculateLargestCompleteSubtree(root.getLeft());
TreeInfo<TKeyType, TValueType> rightInfo = calculateLargestCompleteSubtree(root.getRight());
// case 1: not a complete tree.
if (!leftInfo.isComplete || !rightInfo.isComplete)
{
// Only one subtree is complete. Set it as the max and return false.
if(leftInfo.isComplete) {
max = Math.max(max, leftInfo.size);
}
else if(rightInfo.isComplete)
{
max = Math.max(max, rightInfo.size);
}
return new TreeInfo<>(false, -1);
}
// case 2: both subtrees complete
int delta = Math.abs(leftInfo.size - rightInfo.size);
if (delta <= 1)
{
// both are complete but R could be 1 greater...use L tree.
size = leftInfo.size + 1;
max = Math.max(max, size);
return new TreeInfo<>(true, size);
}
else
{
// limit to size of R + 1 if L - R > 1, otherwise L
if(leftInfo.size > rightInfo.size)
{
max = Math.max(max, leftInfo.size);
size = rightInfo.size + 1;
}
else
{
max = Math.max(max, rightInfo.size);
size = leftInfo.size;
}
return new TreeInfo<>(true, size + 1);
}
}
答案 6 :(得分:0)
python中的一种简单的递归方法。我已经测试了几棵树,到目前为止工作正常。
# return (is_complete, max_height_so_far, is_perfect)
def is_complete_tree(node):
# null
if not node:
return (True, -1, True)
left_subtree = is_complete_tree(node.left_child)
right_subtree = is_complete_tree(node.right_child)
# if any of subtrees isn't complete, current tree is not complete
if not left_subtree[0] or not right_subtree[0]:
return (False, max(left_subtree[1], right_subtree[1]), False)
# if both subtrees are complete, there are 2 cases in order for current tree to be complete
# case 1: subtrees with same height
# left subtree must be perfect
if left_subtree[1] == right_subtree[1] and left_subtree[2]:
return (True, left_subtree[1] + 1, right_subtree[2])
# case 2: left subtree taller by 1
# right subtree must be perfect
if left_subtree[1] == right_subtree[1] + 1 and right_subtree[2]:
return (True, left_subtree[1] + 1, False)
# otherwise not complete
return (False, max(left_subtree[1], right_subtree[1]), False)
答案 7 :(得分:0)
这是我建议的解决方案:要点是跟踪子树的当前节点数,当前高度和最大高度,直到该点为止。
利用当前的节点数和高度,可以通过直接子节点各自的信息来计算根的节点数和高度,同时考虑子节点的高度之间的关系以及它们是否为完美的子树。
解决方案是O(n)时间复杂度和O(h)空间复杂度(函数调用堆栈从根到通过唯一路径到当前节点相对应)。
这是此解决方案的Python代码,您可以找到带有示例here的完整摘要:
from collections import namedtuple
class BTN():
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
# number of nodes for a perfect tree of the given height
def max_nodes_per_height(height: int) -> int:
return 2**(height + 1) - 1
def height_largest_complete_subtree(root: BTN) -> int:
CompleteInformation = namedtuple('CompleteInformation', ['height', 'num_nodes', 'max_height'])
def height_largest_complete_subtree_aux(root: BTN) -> CompleteInformation:
if (root is None):
return CompleteInformation(-1, 0, 0)
left_complete_info = height_largest_complete_subtree_aux(root.left)
right_complete_info = height_largest_complete_subtree_aux(root.right)
left_height = left_complete_info.height
right_height = right_complete_info.height
if (left_height == right_height):
if (left_complete_info.num_nodes == max_nodes_per_height(left_height)):
new_height = left_height + 1
new_num_nodes = left_complete_info.num_nodes + right_complete_info.num_nodes + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
else:
new_height = left_height
new_num_nodes = max_nodes_per_height(left_height)
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
elif (left_height > right_height):
if (max_nodes_per_height(right_height) == right_complete_info.num_nodes):
new_height = right_height + 2
new_num_nodes = min(left_complete_info.num_nodes, max_nodes_per_height(right_height + 1)) + right_complete_info.num_nodes + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
else:
new_height = right_height + 1
new_num_nodes = max_nodes_per_height(right_height) + right_complete_info.num_nodes + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
elif (left_height < right_height):
if (left_complete_info.num_nodes == max_nodes_per_height(left_height)):
new_height = left_height + 1
new_num_nodes = left_complete_info.num_nodes + max_nodes_per_height(left_height) + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
else:
new_height = left_height
new_num_nodes = (max_nodes_per_height(left_height - 1) * 2) + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
return height_largest_complete_subtree_aux(root).max_height