美文网首页
二叉树1-二叉树的深度、层序遍历和BST的验证、查找与删除

二叉树1-二叉树的深度、层序遍历和BST的验证、查找与删除

作者: rensgf | 来源:发表于2021-03-30 21:28 被阅读0次

    104.二叉树的最大深度

    给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
    思路一:递归DFS
    每个节点的最大深度等于其左右子树最大深度+1。
    maxDepth(root)=max(maxDepth(root->left),maxDepth(root->right))+1

        int maxDepth(TreeNode* root) {
            if(!root)
                return 0;
            return max(maxDepth(root->left),maxDepth(root->right))+1;
        }
    

    如果递归过深,会产生很多临时变量,导致栈溢出。所以如何将递归的DFS转为非递归?递归转为非递归通常用栈来实现。
    思路二:非递归DFS

        int maxDepth(TreeNode* root) {
            if(!root)
                return 0;
            int mm=0;#最大深度
            stack<pair<TreeNode*,int>> s;#记录每个节点的深度
            s.push({root,1});
            while(!s.empty())
            {
                pair<TreeNode*,int> t=s.top();
                s.pop();
                TreeNode* tmp=t.first;
                int n=t.second;
                if(n>mm)
                    mm=n;
                if(tmp->left)
                    s.push({tmp->left,n+1});
                if(tmp->right)
                    s.push({tmp->right,n+1});
            }
            return mm;
        }
    

    以上方法都是用DFS的方法,最直观的方法是对二叉树的每一层进行遍历,即二叉树的层序遍历,用的是BFS的方法,即使用队列其求解。

    102.二叉树的层序遍历

    BFS,广度/宽度优先。说白了就是从上到下,先把每一层遍历完之后再遍历一下一层。
    层序遍历可以用DFS的方法实现,但是要保存每个节点的深度值,使用二元组 (node, level) 来表示状态。而BFS不用。

    • 根元素入队
    • 当队列非空时
      - 求队列长度
      - 该长度内节点为同一深度
      - 下一级节点入队
    vector<vector<int>> levelOrder(TreeNode* root) {
            vector<vector<int>> result;
            if(!root)
                return result;
            queue<TreeNode*> q;
            q.push(root);
            while(!q.empty())
            {
                vector<int> cur;
                int l=q.size();
                for(int i=0;i<l;i++)
                {
                    TreeNode* tmp=q.front();
                    q.pop();
                    cur.push_back(tmp->val);
                    if(tmp->left) q.push(tmp->left);
                    if(tmp->right) q.push(tmp->right);
                }
                result.push_back(cur);
            }
            return result;
        }
    

    98.验证二叉搜索树

    二叉搜索树的左子树小于根节点,右子树大于根节点。它的左、右子树也分别为二叉搜索树。
    思路一:中序遍历
    因为二叉树的中序遍历为递增数列,所以只要判断中序遍历后是否递增。中序遍历:左-》中-》右。

     bool isValidBST(TreeNode* root) {
            vector<int> vec;
            midorder(root,vec);
            for(int i=0;i<vec.size()-1;i++)
            {
                if(vec[i]>=vec[i+1])
                return false;
            }
            return true;
        }
        void midorder(TreeNode* root,vector<int>& vec)
        {
            if(!root)
                return;
            midorder(root->left,vec);
            vec.push_back(root->val);
            midorder(root->right,vec);
        }
    

    思路二:递归
    错误思想:如果左右子树是二叉搜索树,且左子树根节点值小于中间节点,右子czz树根节点的值大于中间节点,则可以判断为BST。忽略了左右子树内的值与中间节点的大小比较。
    左子树保存节点最大值,右子树保存节点最小值,与中间节点比较可以解决。

        bool isValidBST(TreeNode* root) {
            return isBST(root,LONG_MIN,LONG_MAX);
        }
        bool isBST(TreeNode* root,long mi,long ma)
        {
            if(!root)
                return 1;
            if((mi>=root->val)||(ma<=root->val))
                return 0;
            return isBST(root->left,mi,root->val) && isBST(root->right,root->val,ma);
        }
    

    最大值最小值的数据类型为长整型。

    700.二叉搜索树查找

    给定二叉搜索树(BST)的根节点和一个值。你需要在BST中找到节点值等于给定值的节点。返回以该节点为根的子树。如果节点不存在,则返回 NULL。
    思路一:迭代
    比较给定值与根节点的大小,小于根节点找左子树,大于根节点找右子树,直到子节点为空。

    TreeNode* searchBST(TreeNode* root, int val) {
            TreeNode* new_node=root;
            while(new_node!=nullptr)
            {
                if(val==new_node->val)
                    return new_node;
                if(val>new_node->val)
                    new_node=new_node->right;
                else
                    new_node=new_node->left;
            }
            return nullptr;
        }
    

    思路二:递归

        TreeNode* searchBST(TreeNode* root, int val) {
            if(!root)
                return nullptr;
            if(val==root->val)
                return root;
            if(val>root->val)
                return searchBST(root->right,val);
            else
                return searchBST(root->left,val);
        }
    

    思路二:递归

    450.BST的删除

    给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
    一般来说,删除节点可分为两个步骤:
    1.首先找到需要删除的节点;
    2.如果找到了,删除它。
    说明: 要求算法时间复杂度为 O(h),h 为树的高度。
    难点:如何提前一步搜索,删除节点。还要保持BTS的特性。

    • 如果目标节点大于当前节点值,则去右子树中删除;
    • 如果目标节点小于当前节点值,则去左子树中删除;
    • 如果目标节点就是当前节点,分为以下三种情况:
      1.其无左子:其右子顶替其位置,删除了该节点;
      2.其无右子:其左子顶替其位置,删除了该节点;
      3.其左右子节点都有:其左子树转移到其右子树的最左节点的左子树上,然后右子树顶替其位置,由此删除了该节点。


      左右子节点都有.png
    class Solution {
    public:
        TreeNode* deleteNode(TreeNode* root, int key) {
            if(!root)
                return root;
            if(key==root->val)//找到目标节点
            {
                if(!root->right)
                    return root->left;//让左子树代替该节点
                if(!root->left)
                    return root->right;//让右子树代替该节点
                TreeNode* node =  root->right;//左右子树都存在,左子树移接到右子树最左节点
                while(node->left){
                    node=node->left;
                }
                node->left=root->left;//移花接木
                root=root->right;//根节点变为右子树
            }
            if(key>root->val)
                root->right=deleteNode(root->right, key);//目标节点在右子树
            else
                root->left=deleteNode(root->left, key);//目标节点在左子树
            return root;
        }
    };
    

    致谢:感谢知乎万字长文!二叉树入门和刷题看这篇就够了!和梁先生的帮助!

    相关文章

      网友评论

          本文标题:二叉树1-二叉树的深度、层序遍历和BST的验证、查找与删除

          本文链接:https://www.haomeiwen.com/subject/lllghltx.html