104. 二叉树的最大深度(三种解法) 110. 平衡二叉树(两种解法)111. 二叉树的最小深度(两种解法)

    技术2022-07-10  107

    104. 二叉树的最大深度

    题目:

    给定一个二叉树,找出其最大深度。

    二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

    说明: 叶子节点是指没有子节点的节点。

    解法1:递归

    class Solution { public: int maxDepth(TreeNode* root) { if (NULL == root) return 0; int leftDep = maxDepth(root->left) + 1; int rightDep = maxDepth(root->right) + 1; return leftDep > rightDep ? leftDep : rightDep; } };

             在递归中,如果不想用到临时变量,可以选择用max()方法。具体程序可参考如下:

    class Solution { public: int maxDepth(TreeNode* root) { if(root == NULL) { return 0; } return max(maxDepth(root->left), maxDepth(root->right)) + 1; } };

            有时候调用max()方法,程序无法识别,就会想到宏,具体程序可参考如下:

    #define MAX(x,y) ((x)>(y)?(x):(y)) //莫忘最外层括号 class Solution { public: int maxDepth(TreeNode* root) { if (NULL == root) return 0; return MAX(maxDepth(root->left), maxDepth(root->right)) + 1; } };

           但是,这种实现会超出时间限制。为什么呢?

           不由得想说明是宏?是在预编译的时候进行文本替换,那么在MAX的地方,运行时会调用maxDepth()三次:((x)>(y)?(x):(y))。所以当树比较深的时候会超时。因此,宏不要用在递归函数上。

    解法2:用从上到下打印二叉树的思想,深度即层数

    class Solution { public: int maxDepth(TreeNode* root) { if(nullptr == root) return 0; queue<TreeNode*> que; que.push(root); int depth = 0; while(!que.empty()){ depth++; int len =que.size(); while (len--) { TreeNode* node=que.front(); que.pop(); if(node->left!=nullptr) que.push(node->left); if(node->right!=nullptr) que.push(node->right); } } return depth; } };

    解法3:用一个全局变量记录层数,每层判断

    class Solution { public: void cntLevel(TreeNode* root, int curLevel, int& depth) { if (NULL == root) return; if (curLevel > depth) depth = curLevel; cntLevel(root->left, curLevel + 1, depth); cntLevel(root->right, curLevel + 1, depth); } int maxDepth(TreeNode* root) { int depth = 0; cntLevel(root, 1, depth); return depth; } };

            这种方法,没有递归调用,也不用操作具体的节点,效率较高。

    110. 平衡二叉树

    题目:

    给定一个二叉树,判断它是否是高度平衡的二叉树。

    本题中,一棵高度平衡二叉树定义为:

    一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

     解法1:计算数的深度,由上至下

    class Solution { private: int treeDepth(TreeNode* root) { if (NULL == root) return 0; return max(treeDepth(root->left), treeDepth(root->right)) + 1; } public: bool isBalanced(TreeNode* root) { if (NULL == root) return true; return abs(treeDepth(root->left) - treeDepth(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right); } };

    解法2:由下至上,子树不平衡即不平衡

    class Solution { private: bool isBalance(TreeNode* root, int& deep) { if (NULL == root) { deep = 0; return true; } int leftLen, rightLen; if (isBalance(root->left, leftLen) && isBalance(root->right, rightLen) && abs(leftLen - rightLen) <= 1) { deep = max(leftLen, rightLen) + 1; return true; } return false; } public: bool isBalanced(TreeNode* root) { if (NULL == root) return true; int deep = 0; return isBalance(root, deep); } };

            这种思路是在计算长度的时候,及时判断是否为平衡。此思路还有另一种实现,具体如下程序:

    class Solution { private: int depth(TreeNode* root, bool& flag) { if (NULL == root) { flag = true; return 0; } bool left, right; int leftLen = depth(root->left, left); int rightLen = depth(root->right, right); if (left && right && abs(leftLen - rightLen) <= 1) { flag = true; return max(leftLen, rightLen) + 1; } flag = false; return -1; //无效,无须计算 } public: bool isBalanced(TreeNode* root) { if (NULL == root) return true; bool flag; depth(root, flag); return flag; } };

    111. 二叉树的最小深度

    题目:

    给定一个二叉树,找出其最小深度。

    最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

    说明: 叶子节点是指没有子节点的节点。

    题目要点:

    最小深度定义为到最近叶子节点的深度,当左右子树都为空,最小深度才为1。

    解法1:分类讨论子节点情况

    class Solution { public: int minDepth(TreeNode* root) { if (NULL == root) return 0; int left = minDepth(root->left); int right = minDepth(root->right); if (0 == left && 0 == right) //1为根节点所在的深度 return 1; if (0 == left || 0 == right) return 0 == left ? right + 1 : left + 1; return min(left, right) + 1; } };

          这种解法根据返回情况写的很详细直白,理解后返回判断可以进一步简写如下:

    class Solution { public: int minDepth(TreeNode* root) { if (NULL == root) return 0; int left = minDepth(root->left); int right = minDepth(root->right); if (0 == left || 0 == right) return max(left, right) + 1; //1为根节点所在的深度 return min(left, right) + 1; } };

            甚至可以直接简写为一个三元式,具体程序如下:

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

            其中(left && right)不成立时,说明左右子节点至少有一个为空,即left和right至少有一个为0,  1+left+right数值上等于要求的数,没有别的特殊意义。

            有很多同学第一次写,很容易写成如下程序(本题的错误解法,通不过的测试例如[1,2]),这就是没有好好理解最小深度的定义。

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

    解法2:用从上至下打印二叉树的队列思路,遇到叶子节点短路处理

    class Solution { public: int minDepth(TreeNode* root) { if(NULL == root) return 0; queue<TreeNode*> que; que.push(root); int depth = 0; while(!que.empty()){ int len = que.size(); while (len--) { TreeNode* node = que.front(); que.pop(); if(NULL == node->left && NULL == node->right) return depth + 1; if(node->left) que.push(node->left); if(node->right) que.push(node->right); } depth++; } return depth; } };

             这种思路,处理到第一个叶子节点就结束了,效率较好。

    Processed: 0.010, SQL: 9