[leetcode] 二叉树相关题目

  • 中序遍历二叉树
    • 递归做法
    void inorderTraversalBase(TreeNode* root, vector<int>& res){
        if(root == NULL)
            return;
        inorderTraversalBase(root->left, res);
        res.push_back(root->val);
        inorderTraversalBase(root->right, res);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        inorderTraversalBase(root, res);
        return res;
    }
    
    • 非递归做法, 利用栈现将左节点存起来。前序也可以基于这个framework去修改。将加入数组的操作放在while(root) 内即可。
    vector<int> inorderTraversalIterating(TreeNode* root){
        stack<TreeNode* > stack1;
        vector<int> res;
        while(root != NULL || !stack1.empty()){
            while(root){
                stack1.push(root);
                root = root->left;
            }
            // 没有左孩子,则当前节点就应该加入队列中。
            root = stack1.top();
            res.push_back(root->val);
            stack1.pop();
            root = root->right;
        }
        return res;
    }
    
  • 二叉树层次序遍历
    • 每一层对应一个vector, 最终返回一个vector<vector<>>类型的数据。
    • 层次序遍历还是使用queue。
    • 关键在于如何计算每层的节点个数。我们利用nums计数当前level的总节点的个数。用next_level_num计算下一层的个数。nums初始化为1.
    • 当当前节点不为null的时候意味着下一层有两个节点(NULL也算一个),所以next_level_nums +=2
    • 当已经遍历完本层节点后,则开始遍历下一层节点.
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        vector<int> cur_level;
        int nums = 1;
        int count = 0;
        queue<TreeNode*> nodes;
        nodes.push(root);
        int next_levels_num = 0;
        while(!nodes.empty()){
            TreeNode* cur_node = nodes.front();
            nodes.pop();
            if(cur_node != NULL){
                nodes.push(cur_node->left);
                nodes.push(cur_node->right);
                cur_level.push_back(cur_node->val);
                next_levels_num += 2;
            }
            count += 1;
            if(count == nums){
                nums = next_levels_num;
                next_levels_num = 0;
                count = 0;
                res.push_back(cur_level);
                cur_level = {};
            }
        }
        return res;
    }
    
  • 由前序和中序序列构建二叉树
    • 前提是输入合法并且没有重复的元素
    • 首先利用前序的第一个节点构建一个node, 并根据这个数,将中序,前序序列分为前段后后段。
    • node的左孩子就是根据前段构造的子树。
    • node的右孩子就是根据后段构造的子树。
    • 通过递归的方式来完成整个树的构造。
    TreeNode* buildTreeBase(vector<int>& preorder, vector<int>& inorder,
            int l_pre, int r_pre, int l_in, int r_in){
        if(l_pre > r_pre || l_in > r_in){
            return NULL;
        }
        int root_value = preorder[l_pre];
        TreeNode* root = new TreeNode(root_value);
        int target_l_in = -1;
        for(int i=l_in; i<=r_in;i++){
            if(inorder[i] == root_value){
                target_l_in = i;
                break;
            }
        }
        int num_nodes_left = target_l_in - l_in;
        root->left = buildTreeBase(preorder, inorder, l_pre + 1, l_pre + num_nodes_left ,l_in, target_l_in-1);
        root->right = buildTreeBase(preorder, inorder, l_pre + num_nodes_left + 1, r_pre, target_l_in + 1, r_in);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size() != inorder.size())
            return NULL;
        int size = (int) preorder.size();
        return buildTreeBase(preorder, inorder, 0, size-1, 0, size-1);
    }
    
  • 将一颗二叉树转化成一个链表
    • 将二叉树按照前序遍历的方式转化成一个链表,左孩子都是空,只使用右孩子代表next。
    • 解法1:利用辅助存储空间
      • 我们首先对二叉树进去前序遍历
      • 按照顺序保存前序遍历的节点。
      • 再遍历所有节点,right = next,left= NULL
    • 解法2: 不利用存储空间。
      • 因为我们是按照前序序列构建列表,所以我们可以构造一种新的遍历方式。
      • 先遍历左孩子,再右孩子,再自身节点。
      • 通过上面的递归遍历,我们访问得到的第一个节点就是我们链表中的最后一个节点。访问的最后一个节点就是我们链表中的第一个节点。
      • 针对访问过程中的每个节点,我们保存上一个其访问的节点X。则当前节点的right= X,left=NULL, X=current.
      • 等遍历完成了,则链表也构造完成。
    • 代码:
    void flatten(TreeNode* root) {
        vector<TreeNode*> nodes;
        stack<TreeNode*> stack1;
        TreeNode* cur = root;
        while(cur != NULL || !stack1.empty()){
            while (cur){
                stack1.push(cur);
                nodes.push_back(cur);
                cur = cur->left;
    
            }
            cur = stack1.top();
            stack1.pop();
            cur = cur->right;
        }
        cur = root;
        for(int i=1;i<nodes.size();i++){
            cur->right = nodes[i];
            cur->left = NULL;
            cur = cur->right;
        }
        cur->right = NULL;
    }
    TreeNode* prev = NULL;
    void flattenV2(TreeNode* root){
        if(root == NULL)
            return;
        flattenV2(root->right);
        flattenV2(root->left);
        root->right = prev;
        root->left = NULL;
        prev = root;
    }
    
  • 计算二叉树的深度:
    • 思路:利用递归的方式,depth= max(MAXDEPTH(root->left)+1, MAXDEPTH(root->right) + 1);
    • 代码:
    int maxDepthBase(TreeNode* root, int height){
        if(root == NULL){
            return height;
        }
        return max(maxDepthBase(root->left, height + 1), maxDepthBase(root->right, height + 1));
    }
    int maxDepth(TreeNode* root) {
        return maxDepthBase(root, 0);
    }
    
  • 判断一颗二叉树是否是镜像二叉树。
    • 利用递归的思想。
    • 首先我们定义一种新的遍历方式A:先遍历右节点,再遍历左节点,再是根节点。
    • 如果一棵树是镜像二叉树,那么他前序访问得到的value和A访问得到的value是一致的,则是镜像二叉树。
    • 所以我们只写一个i递归,同时进行两种遍历,判断每一刻他们节点的值是否相同,如果一致相同则是镜像二叉树。
    • 代码:
    bool isSymmetricBase(TreeNode* root1, TreeNode* root2){
        if(root1 == NULL && root2 == NULL)
            return true;
        if(root1 == NULL || root2 == NULL)
            return false;
        return (root1->val == root2->val)
        && isSymmetricBase(root1->left, root2->right)
        && isSymmetricBase(root1->right, root2->left);
    }
    bool isSymmetric(TreeNode* root) {
        return isSymmetricBase(root, root);
    }
    
  • 有多少种不同的二叉搜素树。
    • 如果一个N,代表节点的个数,试计算一共有多少种不同的二叉搜素树。
    • 如果N=1,则有一种方式。
    • 如果N=2,我们选取根节点有两种方式,每种对应的一种解决方案。因为另一个要么是在根节点的左边,要么是在跟节点的右边。2=1+1
    • 如果N=3,我们选取跟节点有三种方式,当根节点=1,右子树个数为0,左子树节点个数为2(两种构造方式)。当跟节点=2,左右各1,当跟节点为3,右子树为2,左子树为0.所以Res=2+1+2=5
    • 所以我们可以总结如下规律: f ( n ) = ∑ i = 1 n f ( i − 1 ) ∗ f ( n − i ) f(n) = \sum_{i=1}^nf(i-1)*f(n-i) f(n)=i=1nf(i1)f(ni)
    • 代码:
    int numTrees(int n) {
        int counts[n+1];
        counts[0] = 1;
        counts[1] = 1;
        counts[2] = 2;
        if(n<=2)
            return counts[n];
        for(int i=3;i<=n;i++){
            int count = 0;
            // 一共是i个点
            for(int j=0;j<i;j++){
                // 选取第j点作为根节点
                count += (counts[j] * counts[i-j-1]);
            }
            counts[i] = count;
        }
        return counts[n];
    }
    
  • 判断一颗二叉树是不是二叉搜索树。
    • 利用的递归的思想。
    • 一开始的取值范围是[Null, null]
    • 在中序遍历的过程中不停的更新范围
    • 判断节点的值是否在该范围中,如果在,继续,如果不在,则可以返回false。
    • 代码:
    bool isValidBSTBase(TreeNode* root, int* min_val, int* max_val){
        if(root == NULL)
            return true;
        if(min_val != NULL && (*min_val) >= root->val)
            return false;
        if(max_val != NULL && (*max_val) <= root->val)
            return false;
        return isValidBSTBase(root->left, min_val, &root->val)
        && isValidBSTBase(root->right, &root->val, max_val);
    }
    bool isValidBST(TreeNode* root) {
        return isValidBSTBase(root, NULL, NULL);
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值