zoukankan      html  css  js  c++  java
  • 111. 二叉树的最小深度

    111. 二叉树的最小深度

    求最小深度/根节点到最近叶子节点的最短路径上的节点数量;

    递归解法

    递归解1(错解)

    尝试考虑:

    在求解的过程中下落到某个树(t)

    • 如果(t)为空, 那么它的最小深度为0;

    • 如果(t)的左子树和右子树都非空, 那么它的最小深度等于(1 + min(h_l, h_r));

    • 如果(t)的左子树为空或右子树为空, 那么它的最小深度等于1;

    可以写出如下代码

    class Solution {
    public:
        int minDepth(TreeNode* root) {
            if(root==nullptr) return 0;
            if(root->left!=nullptr && root->right!=nullptr) return 1 + min(minDepth(root->left), minDepth(root->right));
            return 1;
        }
    };
    

    这显然是错误的, 例如:

    输入:
    [1,2]
    输出
    1
    预期结果
    2
    

    PS: 实际上上面的三条规则是冗余的, 可以化简为:

    • 如果(t)为空, 那么它的最小深度为0;

    • 否则它的最小深度等于(1 + min(h_l, h_r));

    递归解2

    可以让被抛给递归函数的t确保为非空;

    • 如果(t)的左右子树都非空, 则(minDepth = 1 + min(h_l, h_r));
    • 再如果(t)的左右子树都为空, 则(minDepth = 1);
    • 最后对于左右子树一个为空, (minDepth = 1 + minDepth_{非空子树});
    class Solution {
    public:
        int helper(TreeNode* t) {
            if(t->left!=nullptr && t->right!=nullptr) return 1 + min(minDepth(t->left), minDepth(t->right));
            if(t->left==nullptr && t->right==nullptr) return 1;
            return 1 + minDepth((t->left!=nullptr) ? t->left : t->right);
        }
        int minDepth(TreeNode* root) {
            if(root==nullptr) return 0;
            return helper(root);
        }
    };
    
    执行用时 :20 ms, 在所有 C++ 提交中击败了35.52%的用户
    内存消耗 :21.6 MB, 在所有 C++ 提交中击败了5.10%的用户
    

    递归解3

    官方题解

    class Solution {
    public:
        int minDepth(TreeNode* root) {
            if(root==nullptr) return 0;
            if(root->left==nullptr && root->right==nullptr) return 1;
            int minD = INT_MAX;
            if(root->left!=nullptr) minD = min(minD, minDepth(root->left));
            if(root->right!=nullptr) minD = min(minD, minDepth(root->right));
            return 1+minD;
        }
    };
    
    执行用时 :20 ms, 在所有 C++ 提交中击败了35.52%的用户
    内存消耗 :22.1 MB, 在所有 C++ 提交中击败了5.10%的用户
    

    注:

    • 以上题解都注意区分了根节点为空的情况;

    迭代解

    求一棵树的最大深度过程中, 我们记得层序遍历的时候, 可以获得当前遍历的深度, 所以直接可以得出最大深度;

    而在层序遍历时, 也可以知道当前这个节点是不是叶子节点;

    class Solution {
    public:
        int minDepth(TreeNode* root) {
            if(root==nullptr) return 0;
            int minD = INT_MAX;
            deque<TreeNode*> q;
            q.push_back(root);
            int curDepth = 1;
            while(!q.empty()) {
                int n = q.size();
                for(int i=0; i<n; ++i) {
                    TreeNode* t = q.front();
                    q.pop_front();
                    if(t->left==nullptr && t->right==nullptr)
                        minD = min(minD, curDepth);
                    if(t->left!=nullptr) q.push_back(t->left);
                    if(t->right!=nullptr) q.push_back(t->right);
                }
                ++curDepth;
            }
            return minD;
        }
    };
    

    效率都差不多

    执行用时 :20 ms, 在所有 C++ 提交中击败了35.52%的用户
    内存消耗 :21.3 MB, 在所有 C++ 提交中击败了5.10%的用户
    

    上面的方法还有一处愚蠢:

    • BFS层序遍历过程中深度是单调增的, 所以找到的第一个叶子节点深度就是最终要求的minDepth;
    class Solution {
    public:
        int minDepth(TreeNode* root) {
            if(root==nullptr) return 0;
            int minD = INT_MAX;
            deque<TreeNode*> q;
            q.push_back(root);
            int curDepth = 1;
            while(!q.empty()) {
                int n = q.size();
                for(int i=0; i<n; ++i) {
                    TreeNode* t = q.front();
                    q.pop_front();
                    if(t->left==nullptr && t->right==nullptr) {
                        minD = min(minD, curDepth);
                        break;	/// #找到第一个叶子即完成
                    }
                    if(t->left!=nullptr) q.push_back(t->left);
                    if(t->right!=nullptr) q.push_back(t->right);
                }
                ++curDepth;
            }
            return minD;
        }
    };
    

    快了不少

    执行用时 :12 ms, 在所有 C++ 提交中击败了85.32%的用户
    内存消耗 :21.4 MB, 在所有 C++ 提交中击败了5.10%的用户
    
  • 相关阅读:
    《Effective Java》读书笔记八(异常)
    《Effective Java》读书笔记七(通用程序设计)
    《Effective Java》读书笔记六(方法)
    《Effective Java》读书笔记五(枚举和注解)
    《Effective Java》读书笔记四(泛型)
    《Effective Java》读书笔记三(类和接口)
    《Effective Java》读书笔记二(通用方法)
    AngularJS的directive(指令)配置选项说明
    angularJS常见问题汇总
    angular指令中,require和transclude同时设置为true时的作用
  • 原文地址:https://www.cnblogs.com/owxc/p/12465961.html
Copyright © 2011-2022 走看看