104. 利用后序遍历(非递归)求二叉树的最大深度

104.二叉树的最大深度

利用后序遍历的非递归算法

后序遍历在出入栈是,是先将左孩子进栈,处理完毕后出栈,再将右孩子入栈,最后再处理根结点。所以在非递归的后序遍历过程中,栈的深度即为当前的深度。利用这个特性,只需要遍历代码中记录最大深度即可。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int maxDepth(TreeNode* root) {
        /*
        本算法使用非递归的后序遍历。利用非递归的后序遍历算法的特性,对于一个节点:先把左入栈,随后出栈,再让右出栈。
        这样保证在遍历过程中,栈的高度为树的深度。所以遍历就完了,加一句记录最大深度的代码即可。
        时间复杂度为O(n),其中n为树节点个数。
        空间复杂度为O(n),其中n为树的深度。好吧好像和递归的没什么区别。当作学习了
        */
        stack<TreeNode*> S;         
        TreeNode* p = root,*r = NULL;   //p为工作指针,r指向最近访问的节点。
        int height = 0;                 //一开始树的深度记做 0 
        
        while(p||!S.empty()){           //当p为空(访问完某一点后才会被置空)或栈为空(开始或没有树结点时为空)才会退出循环。
            if(p){                      //走到最左边
                S.push(p);
                height = max(height,(int)S.size());     //栈的深度为当前节点的深度,记录那个最大的
                p = p->left;
            }else{
                p = S.top();                        //读取栈顶指针(非出栈)
                if(p->right&&p->right!=r)           //如果当前节点有右孩子且右孩子没被访问过的话
                    p = p->right;                   
                else{
                    S.pop();
                    //visit(p->data);                        
                    r = p;                          //记录最近访问的指针
                    p = NULL;                       //每次出栈 == 遍历完以该结点为根的子树,需要将p设置为NULL,为了后面要退出循环。
                }
            }
        }
        return height;
        
    }
};

接下来是一些比较常规的方法。

深度优先搜索

二叉树的深度优先遍历有三种,前中后。下面这种方法和上面差不多,用的是后序遍历。只不过是递归和非递归的区别而已。
在思考树的递归时,不用想那么复杂,因为树本身就是一个递归定义的数据结构,思考时考虑典型的三个节点(根,左孩子,右孩子)即可

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

在访问到叶子结点时,return max(0,0)+1;

  • 时空复杂度同上非递归版本

广度优先搜索

就是层次遍历

写了一半发现没有官方来的简洁明了,所以下面是官方代码。

官方代码通过增加一个sz变量,记录到每一层的个数。

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        queue<TreeNode*> Q;
        Q.push(root);
        int ans = 0;
        while (!Q.empty()) {
            int sz = Q.size();
            while (sz > 0) {	//分为内外循环,内循环每次只处理一层结点。
                TreeNode* node = Q.front();Q.pop();
                if (node->left) Q.push(node->left);
                if (node->right) Q.push(node->right);
                sz -= 1;
            }
            ans += 1;
        } 
        return ans;
    }
};

时间复杂度:O(n)。n 为二叉树的节点个数。每个节点只会被访问一次。
空间复杂度:O(n)。此方法空间的消耗取决于队列存储的元素数量。

你可能感兴趣的:(LeetCode,leetcode)