二叉树进阶相关题目

1.606. 根据二叉树创建字符串

根据题目描述,当右子树为空的情况括号要省略,左子树为空不能省略

class Solution {
public:
    void _tree2str(TreeNode*root, string &s)
    {
        if(root == nullptr)
        return;
        s += to_string(root->val);

        if(root->left != nullptr || root->right != nullptr)
        {
            s += '(';
            _tree2str(root->left,s);
            s += ')';

        }
        if (root->right != nullptr)
       {
            s+='(';
            _tree2str(root->right,s);
              s+=')';
       }
           
        
    }
    string tree2str(TreeNode* root) {
        string s;
        _tree2str(root,s);
        return s;
    }
};

2.102. 二叉树的层序遍历

该提有两种思路

1.用队列,队列记录当前队列的大小,出队时(出队列大小),在入队具体如下图:

 具体代码如下:

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
            vector<vector<int>> vv;
            if(root == nullptr)
            return vv;
            queue<TreeNode*> q;
            q.push(root);
            while(!q.empty())
            {
                int sz = q.size();  //记录每次队列大小
                vector<int> v;
                while(sz--)
                {
                    TreeNode* tmp = q.front();
                     q.pop();

                    v.push_back(tmp->val);  
                    if(tmp->left)
                    q.push(tmp->left);
                    if(tmp->right)
                    q.push(tmp->right);
                }
                vv.push_back(v);
                v.clear();
            }
            return vv;
    }
};

2.用两个数组,类似滚动数组,思路如下图:

 具体代码如下:

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
            vector<vector<int>> vv;
            if(root == nullptr)
            return vv;
            vector<TreeNode*> v1,v2;
            v1.push_back(root);
            while(!v1.empty() || !v2.empty())
            {
                for(size_t i = 0; i< v1.size(); ++i)
                {
                    if(v1[i]->left)
                    v2.push_back(v1[i]->left);
                    if(v1[i]->right)
                    v2.push_back(v1[i]->right);
                }
                vector<int> tmp;
                for(size_t i = 0 ; i< v1.size(); ++i)
                {
                    tmp.push_back(v1[i]->val);
                }
                vv.push_back(tmp);
                swap(v1,v2);
                v2.clear();
            }
            return vv;
    }
};

3.236. 二叉树的最近公共祖先

该提思路有两种:

1.如果这两个节点一个在我左子树,一个在我右子树,那么该节点就是祖先节点代码如下:

class Solution {
public:
    bool find(TreeNode* root,TreeNode* x) //查找节点
    {
        if(root == nullptr)
        return false;

        if(root == x)
        return true;

        return find(root->left,x) || find(root->right,x);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
    {
        if(root == nullptr)
        return nullptr;
        if(root == p || root == q)   //如果root == p 或者 root == q就是祖先
        return root;
        bool isPleft,isPright,isQleft,isQright;  //判断p,q是在左子树还是右子树

        isPleft = find(root->left,p);
        isPright = !isPleft;
        
        isQleft = find(root->left,q);
        isQright = !isQleft;

        if((isPleft && isQright) || (isPright && isQleft)) //一左一右该节点就是祖先
        return root;

        else if(isPleft && isQleft)  //都在左,递归左子树
        return lowestCommonAncestor(root->left,p,q);

        else if(isPright && isQright) //都在有,递归右子树
        return lowestCommonAncestor(root->right,p,q);

        else
        return nullptr;
    }
};

 2.保存节点的路径,代码如下

class Solution {
public:
    bool GetPath(TreeNode* root, TreeNode* x,stack<TreeNode*>& st)
    {
        if(root == nullptr)
        return false;
        st.push(root);

        if(root == x)
        return true;

        if(GetPath(root->left,x,st))
        return true;
        if(GetPath(root->right,x,st))
        return true;

        st.pop();
        return false;
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        stack<TreeNode*> pPath,qPath;

        GetPath(root,p,pPath);
        GetPath(root,q,qPath);
        while(pPath.size() != qPath.size())
        {
            if(pPath.size() >qPath.size())
            {
                pPath.pop();
            }
            else
            {
                qPath.pop();
            }
        }
        while(pPath.top() != qPath.top())
        {
            pPath.pop();
            qPath.pop();
        }
        return qPath.top();
    }
};

4.JZ36 二叉搜索树与双向链表

class Solution {
public:
    void _Convert(TreeNode* root,TreeNode*& head,TreeNode*& pre)
    {
        if(root == nullptr)
            return;
        
        _Convert(root->left,head,pre);
        //链接
        if(head == nullptr)
        {
            pre = root;
            head = root;
        }
        else
        {
            pre->right = root;
            root->left = pre;
            pre = root;
        }
        _Convert(root->right,head,pre);
    }
    TreeNode* Convert(TreeNode* pRootOfTree) {
        TreeNode* head = nullptr, *pre = nullptr;
        _Convert(pRootOfTree,head,pre);
        return head;
    }
};

6. 根据一棵树的前序遍历与中序遍历构造二叉树。​​​​​​105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)​​​​​​

 

代码如下:

class Solution {
public:
    TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int &prei,int ibegin,int iend)
    {
        if(ibegin > iend) //如果开始区间位置大于结束区间,说明没有这个区间
        return nullptr;

        TreeNode* root = new TreeNode(preorder[prei]);  //一上来先确定根节点

        int rooti = ibegin;

        while(rooti <= iend)   //找到根节点在中序遍历的位置,确定区间
        {
            if(preorder[prei] == inorder[rooti])
                break;

            else
                ++rooti;
        }

        ++prei;
        //[ibegin,rooti-1][rooti][rooti+ 1,iend]
        root->left = _buildTree(preorder,inorder,prei,ibegin,rooti -1);
        root->right = _buildTree(preorder,inorder,prei,rooti + 1,iend);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
            int prei = 0;
            return  _buildTree(preorder,inorder,prei,0,inorder.size() -1);
    }
};

7. 根据一棵树的中序遍历与后序遍历构造二叉树。

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)

这个题跟上一个题类似:但是要注意的是,后序开始位置要从最后的位置开始从后向前构建子树,构建时要先构建右子树再构建左子树

class Solution {
public:
    TreeNode* _buildTree(vector<int>& postorder, vector<int>& inorder,int &prei,int ibegin,int iend)
    {
        if(ibegin > iend)
        return nullptr;

        TreeNode* root = new TreeNode(postorder[prei]);

        int rooti = ibegin;
        while(rooti <= iend)
        {
            if(postorder[prei] == inorder[rooti])
            break;

            else 
            ++rooti;
        }

        --prei;
        root->right = _buildTree(postorder,inorder,prei,rooti + 1,iend);
        root->left = _buildTree(postorder,inorder,prei,ibegin,rooti -1);
        
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
         int prei = postorder.size() -1;
         return  _buildTree(postorder,inorder,prei,0,inorder.size() -1);
    }
};

8. 二叉树的前序遍历,非递归迭代实现 。

144. 二叉树的前序遍历 - 力扣(LeetCode) (leetcode-cn.com)

          

   class Solution {
    public:
        vector<int> preorderTraversal(TreeNode* root) {
            //解法1:遍历所有左子树,弹栈,遍历右子树。//子问题  时间复杂度为O(N) 空间复杂度为O(N)
           /* 
            vector<int> v;
            stack<TreeNode*> st;
            auto cur = root;
            while(cur != nullptr || !st.empty())
            {
                while(cur!= nullptr) // 入所有的左节点到栈
                {
                    st.push(cur);
                    v.push_back(cur->val);  //每次入的时候打印
                    cur =  cur->left;
                }

                auto top = st.top();   //走到这说明左节点全部入栈,在让最后的左节点的右孩子入栈,重复
                st.pop();
                cur = top->right; //精华
            }
            return v;
            */
            //解法2:morris神级遍历,时间复杂度为O(N),空间复杂度为O(1)
            vector<int> v;
            TreeNode* cur = root;
            TreeNode* MostRigth = nullptr;
            while(cur != nullptr)
            {
                MostRigth = cur->left;
                if(MostRigth != nullptr)
                {
                    while(MostRigth->right != nullptr && MostRigth->right != cur)
                     {
                          MostRigth = MostRigth->right;
                     }
                    if(MostRigth->right == nullptr)
                     {
                        v.push_back(cur->val);
                        MostRigth->right = cur;
                        cur = cur ->left;
                        continue; //精华
                     }   
                    else
                    {
                      MostRigth->right = nullptr;
                    }
                }
                else{
                     v.push_back(cur->val);
                }
               
                cur = cur->right;
            }
            return v;
        }
    };

9. 二叉树中序遍历 ,非递归迭代实现。

 二叉树的中序遍历 - 力扣(LeetCode) (leetcode-cn.com)

跟前序遍历一样,知识插入向量(vector)的时机不同

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        //解法1:让左节点入栈,在让右节点入栈
      /*  vector<int> v;
        stack<TreeNode*> st;
        auto cur = root;
        while(cur != nullptr || !st.empty())
        {
            while(cur != nullptr)
            {
                st.push(cur);
                cur = cur->left;
            }
            TreeNode* top = st.top();
            st.pop();
            v.push_back(top->val);
            cur = top->right;
        }
        return v;

    */
    //解法二:morris遍历
        vector<int> v;
        TreeNode* cur = root;
        TreeNode* MostRight = nullptr;
        while(cur != nullptr)
        {
            MostRight = cur ->left;
            if(MostRight != nullptr)
            {
                while(MostRight->right !=  nullptr && MostRight->right != cur)
                {
                    MostRight = MostRight->right;
                }
                if(MostRight->right == nullptr)
                {
                    MostRight->right = cur;
                    cur = cur->left;
                    continue;
                }
                else
                {
                    MostRight->right = nullptr;
                }
            }
            v.push_back(cur->val);
            cur = cur ->right;
        } 
        return v;
      }     
};

10. 二叉树的后序遍历 ,非递归迭代实现。

145. 二叉树的后序遍历 - 力扣(LeetCode) (leetcode-cn.com)

后序遍历需要注意的是:遍历跟节点,第一次的时候不能pop,不然找不到右子树,当第一次遍历到该节点的时候才pop

class Solution {
public:
    void AddMostRight(vector<int> &v,TreeNode* root)
    {
        vector<int>tmp;
        while(root != nullptr)
        {
            tmp.push_back(root->val);
            root = root->right;
        }
        reverse(tmp.begin(),tmp.end());
        for(size_t i = 0; i < tmp.size();++i)
        {
            v.push_back(tmp[i]);
        }
    }
    vector<int> postorderTraversal(TreeNode* root) 
    {
        //解法1:让左节点入栈
        /*
        vector<int> v;
        stack<TreeNode*> st;
        auto cur = root;
        TreeNode* pre = nullptr;
        while( cur !=nullptr || !st.empty())
        {
            while(cur != nullptr)
            {
                st.push(cur);
                cur = cur->left;
            }

            TreeNode* top = st.top();
            if(top->right == nullptr || top->right == pre)
            {
                st.pop();
                pre = top;
                v.push_back(top->val);
            }
            else
            {
                cur = top ->right;
            }
            */
            //解法二:morris遍历
        vector<int> v;
        TreeNode* cur = root;
        TreeNode* MostRight = nullptr;
        while(cur != nullptr)
        {
            MostRight = cur ->left;
            if(MostRight != nullptr)
            {
                while(MostRight->right !=  nullptr && MostRight->right != cur)
                {
                    MostRight = MostRight->right;
                }
                if(MostRight->right == nullptr)
                {
                   
                    MostRight->right = cur;
                    cur = cur->left;
                    continue;
                }
                else
                {
                    MostRight->right = nullptr;
                    AddMostRight(v,cur->left);
                }
            }
            cur = cur ->right;
        } 
        AddMostRight(v,root);
        return v;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值