Given a Binary Tree, find if there exist edge whose removal creates two trees of equal size.
Examples:
Input : root of following tree 5 / 1 6 / / 3 7 4 Output : true Removing edge 5-6 creates two trees of equal size Input : root of following tree 5 / 1 6 / 7 4 / 3 2 8 Output : false There is no edge whose removal creates two trees of equal size.
To find whether such an edge exists, we need to find if there is at least one node that meets the following property.
either this node's left subtree or right subtree has exactly half of the total number of nodes in the given binary tree.
Solution 1. Top down, O(n^2) runtime
1. Count the total number of nodes in given binary tree in O(n) time.
2. from top to bottom, check each node to see if it meets the required property. Each check takes O(n) time, so to check
all nodes, it takes O(n^2) time.
The bottleneck in this algorithm is the O(n) of checking required property operation. For any node, this algorithm recounts
the total number of nodes of its left and right subtree, FROM SCRATCH. For example, for node A and its left child B,
to check if A meets the property, we need to count how many nodes there are in A's left subtree;
to check if B meets the property, we need to count how many nodes there are in B's left/right subtree.
B's subtree nodes are counted twice already: once for when counting A's left subtree; once for when counting B's subtrees.
To avoid this redundant work, we should count bottom up and use memoization to get the number of nodes of given node's subtree in O(1) time.
This is demonstrated in Solution 2.
1 public class RemoveEdgeToEqualSize { 2 public boolean isAnySuchEdgeInefficient(TreeNode root) { 3 int totalNodes = countTotalNodes(root); 4 return checkAllNodes(root, totalNodes); 5 } 6 private int countTotalNodes(TreeNode node) { 7 if(node == null) { 8 return 0; 9 } 10 int count = 1; 11 count += countTotalNodes(node.left); 12 count += countTotalNodes(node.right); 13 return count; 14 } 15 private boolean checkOneNode(TreeNode node, int totalNodes) { 16 if(node == null) { 17 return false; 18 } 19 int leftSubtreeNodes = countTotalNodes(node.left); 20 if(leftSubtreeNodes * 2 == totalNodes) { 21 return true; 22 } 23 int rightSubtreeNodes = countTotalNodes(node.right); 24 if(rightSubtreeNodes * 2 == totalNodes) { 25 return true; 26 } 27 return false; 28 } 29 private boolean checkAllNodes(TreeNode node, int totalNodes) { 30 if(node == null) { 31 return false; 32 } 33 if(checkOneNode(node, totalNodes)) { 34 return true; 35 } 36 return checkAllNodes(node.left, totalNodes) || checkAllNodes(node.right, totalNodes); 37 } 38 }
Solution 2. Bottom up, O(n) runtime
1. Count the total number of nodes in given binary tree in O(n) time.
2. From bottom to top, for each node A, treat it as a root node and count the total number of nodes in this subtree recursively.
3. For each node A, check if there exists an edge that halves the given input tree in this subtree of root A. If any of the 3 is true,
then there exists such an edge in subtree of root A.
a. subtree of root A has half of all nodes of the given input tree.
b. there exists such an edge in A's left subtree.
c. there exists such an edge in A's right subtree.
For each node A, it takes O(1) time to calcuate its total number of nodes in subtree of root A. It also takes O(1) time to deterimine
if there exists such an edge in subtree of root A. So it takes O(n) time to check all nodes in given binary tree.
1 class ReturnInfo { 2 int totalCnt; 3 boolean isAnySuchEdge; 4 ReturnInfo(int t, boolean b) { 5 totalCnt = t; 6 isAnySuchEdge = b; 7 } 8 } 9 public class RemoveEdgeToEqualSize { 10 public boolean isAnySuchEdgeEfficient(TreeNode root) { 11 int totalNodes = countTotalNodes(root); 12 return recurHelper(root, totalNodes).isAnySuchEdge; 13 } 14 private ReturnInfo recurHelper(TreeNode node, int totalNodes) { 15 ReturnInfo ret = new ReturnInfo(0, false); 16 if(node == null) { 17 return ret; 18 } 19 ReturnInfo left = recurHelper(node.left, totalNodes); 20 ReturnInfo right = recurHelper(node.right, totalNodes); 21 ret.totalCnt = 1 + left.totalCnt + right.totalCnt; 22 ret.isAnySuchEdge = ret.totalCnt * 2 == totalNodes || left.isAnySuchEdge || right.isAnySuchEdge; 23 return ret; 24 } 25 }