简体   繁体   English

提高这种二叉树算法的复杂度

[英]Improving this binary tree algorithm complexity

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.我的工作解决方案是这样工作的:functionlongestPath 找到最长的路径,function checkLengths 遍历所有节点,跟踪路径的长度,每次发现只有一个子节点或没有子节点时,它会检查长度之间的差异当前路径的长度和最长路径的长度大于 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.该解决方案的复杂度为 O(2n),因为在最坏的情况下,每个节点都必须访问两次,一次用于最长路径 function,一次用于长度检查 function。 I would like to improve the solution to O(n) but I'm having an hard time figuring out how to do so.我想改进 O(n) 的解决方案,但我很难弄清楚如何做到这一点。

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.编辑:我的解决方案仍然是 O(n) 但我想通过只访问每个节点一次而不是两次来优化它以找到解决方案。

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;
}

Some remarks:一些备注:

  • O(2n) is the same as O(n) O(2n) 与 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 (ie 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.缺点是它使用了更多的 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
}

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. else 存储不同的长度,如果任何其他长度与两个存储的长度不同,你就完成了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM