【LeetCode之树总结】 树类型所有题总结

文章目录


Leetcode上面关于树类型的题总结

94. 二叉树的中序遍历

image-20201110144251637

image-20201110144257359

二叉树的遍历

二叉树的前序遍历是根左右,中序遍历是左根右,后序遍历是左右根,一般前面三种遍历都是递归写法,也可以用迭代。层序遍历是一层一层的遍历,需要利用数据结构队列。

递归写法

/**
 * 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:
    vector<int> ans;
    vector<int> inorderTraversal(TreeNode* root) {
   
        dfs(root);
        return ans;
    }

    void dfs(TreeNode* root){
   
        if (!root) return;
        dfs(root->left);
        ans.push_back(root->val);
        dfs(root->right);
    }
};

非递归写法

  • 遇到一个节点,就把它压栈,并去遍历它的左子树
  • 左子树遍历结束后,从栈顶弹出这个结点并访问
  • 然后按其右指针再去中序遍历该结点的右子树
/**
 * 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:
    vector<int> inorderTraversal(TreeNode* root) {
   
        vector<int> res;
        stack<TreeNode*> stk;
        //终止条件,root为空并且栈空
        while (root || stk.size()){
   
            //遇到节点,压栈并去遍历其左子树
            while (root){
   
                stk.push(root);
                root = root->left;
            }
            //左子树遍历结束,栈顶弹出并访问
            if (stk.size()){
   
                root = stk.top();
                stk.pop();
                res.push_back(root->val);
                //按其右指针继续去中序遍历
                root = root->right;
            }
        }

        return res;
    }


    
};

95. 不同的二叉搜索树 ||

image-20201110153808532

利用二叉搜索树中序遍历有序性

image-20201110162910640

我们可以得出一个有序的序列中,如果把该序列当成二叉搜索树,那么对于如果我们把该序列的任何一个点看成根节点的话,在该点左边的数,在二叉搜索树里面就是该点的左子树,在该点左边的数,在二叉搜索树里面就是该点的右子树。再将问题细小化,左边的序列再去枚举…子问题的划分,这不是递归吗?

时间复杂度

image-20201110162927506

证明略,该时间复杂度是指数级别

代码:

/**
 * 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:
    vector<TreeNode*> generateTrees(int n) {
   
        //特判n=0
        if (!n) return {
   };
        return dfs(1, n);
    }

    vector<TreeNode*> dfs(int l , int r){
   
        if (l > r) return {
   NULL};//终止条件
        vector<TreeNode*> res;
        //枚举[l,r]中每个点作为根节点
        for (int i = l ; i <= r ; i ++){
   
            auto left = dfs(l, i - 1) , right = dfs(i + 1, r);
            //将左子树节点和右子树节点拼接
            for (auto l : left){
   
                for (auto r : right){
   
                    auto root = new TreeNode(i);
                    root->left = l , root->right = r;
                    res.push_back(root);
                }
            }
        }

        return res;
    }
};

96.不同的二叉搜索树

image-20201110163305831

二叉搜索树中序遍历有序性

该题和95题是一个题,该题是求方案数,95题是求所有方案

image-20201111103202347

即序列个数相同组成的二叉搜索树方案数相同

和上题一样,我们可以枚举序列的每个点作为根结点,左子树和右子树能够组成多少方案,由于有了上面的第二个性质,即相同序列组成的二叉搜索树方案相同,我们可以用动态规划的思想来求。

image-20201111103226104

状态表示: f[i]表示i个结点组成二叉搜索树的方案数。
状态方程 f[i] = f[i - 1 - l + 1] * f[r - i - 1 + 1]
递归公式:image-20201111103240001

时间复杂度O(N2),空间复杂度O(N)

代码:

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

        return f[n];
    }
};

98. 验证二叉搜索树

image-20201111103329634

二叉搜索树中序遍历有序性

求得二叉搜索树的中序遍历的结果,再去验证该结果是否是有序的。

时间复杂度O(N) , 空间复杂度O(N)

代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
   
public:
    vector<int> in_order;//记录中序遍历结果
    bool isValidBST(TreeNode* root) {
   
        //特判树空
        if (!root) return true;
        //求树的中序遍历
        dfs(root);
        //验证中序遍历序列是否有序
        for (int i = 0 ; i < in_order.size() ; i ++)
            if (i && in_order[i - 1] >= in_order[i]) 
                return false;

        return true;
    }

    void dfs(TreeNode* root){
   
        if (!root) return ;
        dfs(root->left);
        in_order.push_back(root->val);
        dfs(root->right);
    }

};

中序遍历中验证是否满足二叉搜索树的性质

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

在遍历过程中求一下每个子树的最小值和最大值即可。对于左子树来说,要求得最大值,对于右子树来说,要求最小值。

时间复杂度O(N),空间复杂度O(H),H为树的高度

代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) :
            val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
   
public:
    bool isValidBST(TreeNode* root) {
   
        //特判空树
        if (!root) return true;
        int maxt, mint;
        return dfs(root, maxt, mint);
    }

    bool dfs(TreeNode* root, int &maxt, int &mint)
    {
   
        maxt = mint = root->val;
        //验证左子树
        if (root->left)
        {
   
            int lmax, lmin;
            if (!dfs(root->left, lmax, lmin))
                return false;
            if (lmax >= root->val)
                return false;
            maxt = max(maxt, lmax);
            mint = min(mint, lmin);
        }
        //验证右子树
        if (root->right)
        {
   
            int rmax, rmin;
            if (!dfs(root->right, rmax, rmin))
                return false;
            if (rmin <= root->val)
                return false;
            maxt = max(maxt, rmax);
            mint = min(mint, rmin);
        }
        return true;
    }
};

100. 相同的树

image-20201111200509644

递归

对于两棵树来说,不仅要结构相同,还要各个结点相同。

使用递归求解

代码:

/**
 * 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:
    bool isSameTree(TreeNode* p, TreeNode* q) {
   
        //树都空
        if (!q && !p) return true;
        //树其中一个不空
        if (!q || !p) return false;
        //当前节点值不同
        if (q->val != p->val) return false;
        //左子树和右子树的判断
        return isSameTree(p->left, q->left) && isSameTree(p->right , q->right);
    }
};

101. 对称二叉树

image-20201111211839199

解题

和100题差不多

image-20201111211753931

我们需要先判断根节点,再去看左子树和右子树的情况。

  • 左子树的结点和右子树结点都空,说明对称
  • 左子树和右子树其中一个空,说明不对称
  • 左子树和右子树结点的值不同,说明不对称
  • 递归的去看左子树的左边和右子树的右边 并且 递归的去看右子树的左边和左子树的右边

时间复杂度O(N),空间复杂度O(H),H为树的高度

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
   
public:
    bool isSymmetric(TreeNode* root) {
   
        //空树
        if (!root) return true;
        return dfs(root->left, root->right);
    }

    bool dfs(TreeNode* t1, TreeNode* t2){
   
        //左子树结点和右子树结点都空
        if (!t1 && !t2) return true;
        //其中一个不空
        if (!t1 || !t2) return false;
        //结点值不同
        if (t1->val != t2->val) return false;
        //递归左子树,右子树
        return dfs(t1->left, t2->right
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的内容,推荐的LeetCode顺序是按照类型,优先选择、链表、二分查找、DFS、BFS、动态规划等常见类型目。可以先做2~4道简单,然后再做中等难度的目。在选择目时,可以优先选择目序号小、点赞多、提交成功率高的目,这样可以从简单入手,节省时间。同时,LeetCode每道目都有“模拟面试”功能,可以给自己设定时间限制,如果做不出来可以看答案,然后记住思路后再自己尝试一遍。每种类型目做完10+道后,可以总结规律。 根据引用\[3\]的内容,目可以按照不同的分类进行刷,比如数组与贪心算法、子数组与贪心算法、子序列与贪心算法、数字与贪心、单调栈法、双指针法等。可以根据自己的兴趣和需求选择相应的目进行刷。 综上所述,LeetCode的刷顺序可以按照类型或者目分类进行选择。 #### 引用[.reference_title] - *1* [LeetCode顺序,按标签分类,科学刷!](https://blog.csdn.net/fengyuyeguirenenen/article/details/125099023)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [leetcode指南 & 刷顺序](https://blog.csdn.net/qijingpei/article/details/125561071)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [leetcode-刷顺序推荐](https://blog.csdn.net/weixin_38087674/article/details/114107841)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值