数据结构之树问题汇总

一、二叉树的前序、中序、后序遍历,层序遍历

1.前序遍历

递归解法:根左右

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>res;
        preorder(root,res);
        return res;
    }
    void preorder(TreeNode *root,vector<int>&res){
        if(root==NULL)
            return;
        res.push_back(root->val);
        preorder(root->left,res);
        preorder(root->right,res);
    }
};

迭代解法:先向栈中存入右子树,再访问根,遍历左子树

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>res;
        stack<TreeNode*>s;
        TreeNode *rt=root;
        while(rt||!s.empty()){
            while(rt){
                s.push(rt->right);
                res.push_back(rt->val);
                rt=rt->left;
            }
            rt=s.top();
            s.pop();
        }
        return res;
    }
};

2.中序遍历

递归解法:左根右

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>res;
        inorder(root,res);
        return res;
    }
    void inorder(TreeNode *root,vector<int>&res){
        if(root==NULL)
            return;
        inorder(root->left,res);
        res.push_back(root->val);
        inorder(root->right,res);
    }
};

迭代解法:先向栈中存入根节点,遍历左子树,访问根节点,遍历右子树

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>res;
        stack<TreeNode*>s;
        TreeNode *rt=root;
        while(rt||!s.empty()){
            while(rt){
                s.push(rt);
                rt=rt->left;
            }
            rt=s.top();
            s.pop();
            res.push_back(rt->val);
            rt=rt->right;
        }
        return res;
    }
};

3.后序遍历

递归解法:左右根

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int>res;
        postorder(root,res);
        return res;
    }
    void postorder(TreeNode *root,vector<int>&res){
        if(root==NULL)
            return;
        postorder(root->left,res);
        postorder(root->right,res);
        res.push_back(root->val);
    }
};

迭代解法:先向栈中存入左子树,再访问根,遍历右子树,结果逆序输出

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int>res;
        stack<TreeNode*>s;
        TreeNode *rt=root;
        while(rt||!s.empty()){
            while(rt){
                s.push(rt->left);
                res.push_back(rt->val);
                rt=rt->right;
            }
            rt=s.top();
            s.pop();
        }
        reverse(res.begin(),res.end());
        return res;
    }
};

4.层序遍历 :借助队列实现

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root==NULL) return {};
        vector<vector<int>>res;
        queue<TreeNode*>q;
        q.push(root);
        while(!q.empty()){
            int n=q.size();
            vector<int>temp;
            while(n>0){
                TreeNode *rt=q.front();
                q.pop();
                temp.push_back(rt->val);
                if(rt->left!=NULL) q.push(rt->left);
                if(rt->right!=NULL) q.push(rt->right);
                n--;
            }
            res.push_back(temp);
        }
        return res;
    }
};

二、构建二叉搜索树

1、给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?

思路:一般遇到求多少种的问题,很容易想到动态规划,将问题划分为,总节点个数为i组成的二叉搜索树数目,dp[i]+=dp[j-1]dp[i-j],即左子树数目乘右子树数目,其中j为根节点,j-1就表示左子树节点总数目,i-j表示右子树节点总数目。

class Solution {
public:
    int numTrees(int n) {
        vector<int>dp(n+1);
        dp[0]=1;
        dp[1]=1;
        for(int i=2;i<=n;i++){
            for(int j=1;j<=i;j++){
                dp[i]+=dp[j-1]*dp[i-j];
            }
        }
        return dp[n];
    }
};

2、给定一个整数 n,生成所有由 1 ... n 为节点所组成的 二叉搜索树 

思路:从1到n枚举根节点的值为 i,那么根据二叉搜索树的性质我们可以知道左子树的节点值的集合为[1...i-1],右子树的节点值的集合为[i+1…n],而左子树和右子树的生成相较于原问题是一个序列长度缩小的子问题,因此我们可以想到用递归的方法来解决这道题目。

class Solution {
public:
    vector<TreeNode*> generateTrees(int n) {
        if(n==0) return {};
        return dfs(1,n);
    }
    vector<TreeNode*> dfs(int start,int end){
        if(start>end) return {nullptr};
        vector<TreeNode*>allTrees;
        for(int i=start;i<=end;i++){
            vector<TreeNode*>leftTrees=dfs(start,i-1);
            vector<TreeNode*>rightTrees=dfs(i+1,end);
            for(auto leftTree:leftTrees){
                for(auto rightTree:rightTrees){
                    TreeNode *root=new TreeNode(i);
                    root->left=leftTree;
                    root->right=rightTree;
                    allTrees.push_back(root);
                }
            }
        }
        return allTrees;
    }
};

3.从前序与中序遍历序列构造二叉树

class Solution {
private:
    unordered_map<int,int>index;
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n=preorder.size();
        for(int i=0;i<n;i++){
            index[inorder[i]]=i;
        }
        return myBuildTree(preorder,0,n-1,inorder,0,n-1);
    }
    TreeNode* myBuildTree(vector<int>& preorder,int preleft,int preright,vector<int>& inorder,int inleft,int inright){
        if(preleft>preright) return NULL;
        int preroot=preleft;
        int inroot=index[preorder[preroot]];
        TreeNode *root=new TreeNode(preorder[preleft]);
        int left_tree_size=inroot-inleft;
        root->left=myBuildTree(preorder,preleft+1,preleft+left_tree_size,inorder,inleft,inroot-1);
        root->right=myBuildTree(preorder,preleft+left_tree_size+1,preright,inorder,inroot+1,inright);
        return root;
    }
};

4.从中序与后序遍历序列构造二叉树

class Solution {
private:
    unordered_map<int,int>index;
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int n=inorder.size();
        for(int i=0;i<n;i++){
            index[inorder[i]]=i;
        }
        return myBuildTree(inorder,postorder,0,n-1,0,n-1);
    }
    TreeNode* myBuildTree(vector<int>& inorder, vector<int>& postorder,int inleft,int inright,int postleft,int postright){
        if(inleft>inright) return NULL;
        int postroot=postright;
        int inroot=index[postorder[postroot]];
        TreeNode *root=new TreeNode(postorder[postroot]);
        int left_size=inroot-inleft;
        root->left=myBuildTree(inorder,postorder,inleft,inroot-1,postleft,postleft+left_size-1);
        root->right=myBuildTree(inorder,postorder,inroot+1,inright,postleft+left_size,postright-1);
        return root;
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值