I need to find if all paths of a binary tree that can end(which means all paths that starts from the root and end to a node that has only one child or none) have lengths that differ by no more than one.
My working solution work like this: the function longestPath finds the longest path, the function checkLengths traverse all nodes keeping track of the length of the paths and every time a node with only one child or none is found it checks if the difference between the length of the current path and the length of the longest path is more than 1.
This solution has complexity O(2n) because at worst every node has to be visited twice, once for the longestPath function and once for the lengthCheck function. I would like to improve the solution to O(n) but I'm having an hard time figuring out how to do so.
Edit: my solution is still O(n) but I would like to optimize it to find the solution by visiting each node only once and not twice.
int lengthCheckFlag=1;
int maxLength=-1;
void longestPath(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr && n->right==nullptr){
if(maxLength==-1){
maxLength=currentLength;
}
else{
if(currentLength>maxLength){
maxLength=currentLength;
}
}
}
longestPath(n->left,currentLength 1);
longestPath(n->right,currentLength 1);
}
void checkLengths(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr || n->right==nullptr){
if(abs(maxLength-currentLength)>1){
lengthCheckFlag=0;
}
}
checkLengths(n->left,currentLength 1);
checkLengths(n->right,currentLength 1);
}
bool lengthCheckWrapper(Node n){
if(n==nullptr){
return true;
}
longestPath(n,0);
checkLengths(n,0);
return lengthCheckFlag;
}
Code Update:
int maxP=-1;
int minP=-1;
void minmaxPaths(Node n,int currentLength){
if(n==nullptr){
return;
}
if(n->left==nullptr && n->right==nullptr){
if(maxP==-1){
maxP=currentLength;
minP=currentLength;
}
else{
if(currentLength>maxP){
maxP=currentLength;
}
if(currentLength<minP){
minP=currentLength;
}
}
}
minmaxPaths(n->left,currentLength 1);
minmaxPaths(n->right,currentLength 1);
}
bool lengthCheckWrapper(Node n){
if(n==nullptr){
return true;
}
minmaxPaths(n,0);
if(abs(minP-maxP)<=1){
return true;
}
return false;
}
CodePudding user response:
Some remarks:
- O(2n) is the same as O(n)
- Your functions use different conditions for identifying the potential end of a path: one uses a
&&
operator (wrong) and the other uses a||
operator (correct)
One idea for an alternative algorithm is to make a breadth first traveral. This is interesting, since the constraint really means that all non-perfect nodes (i.e. that have at most one child) must appear in the bottom two levels of the tree.
By consequence, if we find 2 more levels after the first level where we find a non-perfect node, then we have a violation and can stop the traversal.
The down side is that it uses more memory.
Here is how it could be implemented:
int minmaxDepth(Node root) {
if (root == nullptr) {
return 1; // OK
}
std::vector<Node> level, nextLevel;
level.push_back(root);
int minDepth = INT_MAX;
int currDepth = 0;
while (level.size()) {
currDepth ;
nextLevel = {};
for (auto & parent : level) {
if (currDepth < minDepth &&
(parent->left == nullptr || parent->right == nullptr)) {
minDepth = currDepth; // Found a path with minimal length
}
if (parent->left != nullptr) {
nextLevel.push_back(parent->left);
}
if (parent->right != nullptr) {
nextLevel.push_back(parent->right);
}
if (nextLevel.size() && currDepth > minDepth) {
return 0; // Paths have lengths that differ more than 1
}
}
level = nextLevel;
}
return 1; // All nodes were visited: no violation found
}
CodePudding user response:
There is no need to pre-compute the longest path. Compute all path lengths and on the fly,
store the first length,
if some other length differs by more than one, you are done;
else store the differing length, and if any other length differs from the two stored ones, you are done.