做过的二叉树题目思路总结

目录

1、二叉树最小深度

2、在二叉搜索树中搜索指定元素val,并返回以该节点为根的二叉树

3、验证某二叉树是否为二叉搜索树

4、二叉搜索树任意两个不同节点的最小差值(取绝对值)

5、找到包含重复元素的二叉搜索树中出现次数最多的元素

(不使用额外空间)

6、二叉搜索树中的删除操作

7、二叉搜索树中的插入操作


代码随想录上都有这些题目,发这篇文章的目的就是记录自己从零开始学习C++数据结构、刷力扣题的过程。

1、二叉树最小深度

思路1:依据广度优先搜索的性质:广度优先搜索最先找到的叶子节点的深度就是二叉树的最小深度

class Solution {
private:
    int min_depth=0;//二叉树最小深度
public:
    int minDepth(TreeNode* root) {
        if(root==nullptr)return 0;
        if(!root->left&&!root->right)return 1;
        min_depth++;
        queue<TreeNode*>que;
        que.push(root);
        TreeNode*cur=root;
        while(!que.empty()){
            int lens=que.size();
            while(lens--){
                cur=que.front();
                que.pop();
                if(!cur->left&&!cur->right)return min_depth;
                if(cur->left)que.push(cur->left);
                if(cur->right)que.push(cur->right);
            }
            min_depth++;
        }
        return min_depth;
    }
};

思路2:(我的方法)回溯+深度优先搜索+维护一个二叉树最小深度min_depth,每次找到叶子节点,就将此时的深度和最小深度做比较,若该深度小于最小深度,则更新二叉树最小深度。

class Solution {
private:
    int min_depth=INT_MAX;//二叉树最小深度
public:
    void traversal(TreeNode*root,int depth){
        if(root==nullptr)return;
        if(!root->left&&!root->right){
            if(depth<min_depth)min_depth=depth;
            return;
        }
        if(root->left){
            depth++;
            traversal(root->left,depth);
            depth--;
        }
        if(root->right){
            depth++;
            traversal(root->right,depth);
            depth--;
        }
        return;
    }
    int minDepth(TreeNode* root) {
        if(root==nullptr)return 0;
        int depth=1;
        traversal(root,depth);
        return this->min_depth;
    }
};

2、在二叉搜索树中搜索指定元素val,并返回以该节点为根的二叉树

思路:二叉搜索树的性质包括:(二叉搜索树中不存在相同键值的节点)

  1. 非空左子树的所有键值小于其根结点的键值。
  2. 非空右子树的所有键值大于其根结点的键值。
  3. 左、右子树都是二叉搜索树

若val<根节点的值,则root=root->left;若val>根节点的值,则root=root->right;

3、验证某二叉树是否为二叉搜索树

注意:不能以(root->right->val)<(root->val)<(root->left->val)作为判断条件,比如如下二叉树满足该判断条件,但其不是二叉搜索树。

思路1:对二叉搜索树进行中序遍历的结果是升序的

思路2:

4、二叉搜索树任意两个不同节点的最小差值(取绝对值)

我的思路:中序遍历(同第3题思路1),使用vector容器存储中序遍历的结果,时间复杂度:o(n),空间复杂度:o(n)

优化方法:用pre指针记录cur指针的上一个节点,空间复杂度为o(1)

5、找到包含重复元素的二叉搜索树中出现次数最多的元素

(不使用额外空间)

我的思路:用map容器统计二叉树每个元素出现的次数,然后将map容器中出现次数最多的元素放入结果集中。但使用了额外空间。代码如下:

class Compare{
    public:
        bool operator()(pair<int,int>a,pair<int,int>b){
            return a.second>b.second;
        }
};
class Solution {
private:
    vector<int>result;
    unordered_map<int,int>umap;
public:
    void traversal(TreeNode*root){
        if(root==nullptr)return;
        traversal(root->left);
        umap[root->val]++;
        traversal(root->right);
        return;
    }
    vector<int> findMode(TreeNode* root) {
        if(root==nullptr)return result;
        traversal(root);
        vector<pair<int,int>>v(umap.begin(),umap.end());
        sort(v.begin(),v.end(),Compare());
        result.push_back(v[0].first);
        for(int i=1;i<v.size();i++){
            if(v[i].second==v[0].second)result.push_back(v[i].first);
            else break;
        }
        return result;
    }
};

优化方法:

6、二叉搜索树中的删除操作

思路:递归+分情况讨论

函数返回值:删除指定元素后的根节点

递归中止条件:找到要删除的节点,分为以下五种情况:

删除的节点类型执行操作
叶子节点返回nullptr
未找到返回nullptr
只有左子树没有右子树返回左子树
只有右子树没有左子树返回右子树
既有左子树又有右子树首先找到右子树中的最小值,然后将待删除节点的左子树作为待删除节点的右子树中最小值所在节点的左子树,最后返回右子树

单层递归逻辑:根节点的左子树为删除指定元素后的左子树,根节点的右子树同理。

代码如下:

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
       if(root==nullptr)return nullptr;
       if(root->val==key){
            if(!root->left&&!root->right)return nullptr;
            else if(root->left&&!root->right)return root->left;
            else if(!root->left&&root->right)return root->right;
            else{
                TreeNode*cur=root->right;
                while(cur->left)cur=cur->left;
                cur->left=root->left;
                return root->right;
            }
       }
       root->left=deleteNode(root->left,key);
       root->right=deleteNode(root->right,key);
       return root;
    }
};

7、二叉搜索树中的插入操作

关键:向二叉搜索树中插入元素不需要改变原结构。

思路:根据二叉搜索树的性质

递归终止条件:待插入元素的值大于根节点值并且根节点没有右子树,则将插入元素作为根节点的右子树;若待插入元素的值小于根节点值并且根节点没有左子树,则将插入元素作为根节点的左子树。

递归逻辑:

若待插入元素的值大于根节点值,说明应插入的元素在根节点的右子树;

若待插入元素的值小于根节点值,说明应插入的元素在根节点的左子树。

代码如下:

class Solution {
private:
    TreeNode*cur;//插入二叉搜索树的新节点
public:
    void traversal(TreeNode*root,int val){
        if(root->left==nullptr&&root->val>val){
            root->left=cur;
            return;
        }
        if(root->right==nullptr&&root->val<val){
            root->right=cur;
            return;
        }
        if(root->val<val) insertIntoBST(root->right,val);
        else insertIntoBST(root->left,val);
    }
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        cur=new TreeNode(val);
        if(root==nullptr)return cur;
        traversal(root,val);
        return root;
    }
};

8、翻转二叉树

思路:翻转二叉树每个节点的左右子树就能实现二叉树的翻转(注意翻转的是TreeNode*类型的指针,而不是修改节点的值)

9、对称二叉树

思路:具体地,首先将根节点的左节点和右节点入栈。若左子树为空且右子树不为空,return false;若右子树为空且左子树不为空,return false;若左右子树均不为空但值不相同,return false;若左右子树均为空,则continue。最后将左子树的左节点、右子树的右节点、左子树的右节点、右子树的左节点依次入栈,直到栈为空,跳出循环,说明是对称二叉树。

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(root==nullptr)return true;
        if(!root->left&&!root->right)return true;
        if((!root->left&&root->right)||(root->left&&!root->right))return false;
        TreeNode*l=root->left;
        TreeNode*r=root->right;
        stack<TreeNode*>stk;
        stk.push(l);
        stk.push(r);
        while(!stk.empty()){
            l=stk.top();
            stk.pop();
            r=stk.top();
            stk.pop();
            if(!l&&!r)continue;//两节点都为空,return true
            else if(!l&&r||l&&!r)return false;//只存在一个节点,return false
            else if(l->val!=r->val)return false;//两节点都存在且值不相等,return false
            stk.push(l->left);
            stk.push(r->right);
            stk.push(l->right);
            stk.push(r->left);
        }
        return true;
    }
};

10、平衡二叉树

思路:从下至上遍历二叉树,如果底层的节点的左右子树的高度差大于1(即非平衡二叉树),则该二叉树就是非平衡二叉树。实现方式为后序遍历+借助栈实现迭代。

11、二叉树最大深度

思路:广度优先搜索

12、恢复二叉搜索树

问题:一个二叉搜索树的两个节点值被交换了,恢复交换前的二叉树。

我的思路:中序遍历,将节点保存到数组中,对二叉搜索树进行中序遍历的结果应该是升序的,在数组中找到交换的两个节点并交换它们的值。

代码如下:

13、根据描述创建二叉树

题干描述:

我的思路:用哈希表存储节点值及其节点,以便判断该节点是否创建过,未创建过的节点在创建后存储到哈希表中,已经创建过的节点(即出现在哈希表中)则取出即可。同时还需要第二个哈希表存储所有孩子节点,以便找到二叉树的根节点。代码如下:

class Solution {
public:
    TreeNode* createBinaryTree(vector<vector<int>>& descriptions){
      TreeNode*root;
      unordered_map<int,TreeNode*>s;
      unordered_set<int>u;//存放孩子节点
      for(int i=0;i<descriptions.size();i++){
        TreeNode*l;
        if(s.find(descriptions[i][0])==s.end()){
          l=new TreeNode(descriptions[i][0]);
          s[l->val]=l;
        }
        else l=s[descriptions[i][0]];
        TreeNode*r;
        if(s.find(descriptions[i][1])==s.end()){
          r=new TreeNode(descriptions[i][1]);
          s[r->val]=r;
        }
        else r=s[descriptions[i][1]];
        u.emplace(descriptions[i][1]);
        if(descriptions[i][2]==1)l->left=r;
        else l->right=r;        
      }
      for(int i=0;i<descriptions.size();i++){
        if(u.find(descriptions[i][0])==u.end()){
          root=s[descriptions[i][0]];
          break;
        }
      }
      return root;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值