【LeetCode】二叉树以及二叉树递归相关问题汇总

二叉树相关

二叉树的天然递归结构

104. 二叉树的最大深度

题目描述

在这里插入图片描述

题解

左子树的最大深度+右子树的最大深度+1

   int maxDepth(TreeNode* root) {
        if(root==NULL)
        {
            return 0;
        }
        return max(maxDepth(root->left),maxDepth(root->right))+1;
    }

111. 二叉树的最小深度

题目描述

在这里插入图片描述

题解 注意终止条件必须是叶子节点 左右子树为空

注意左右子树不存在的情况 并且计算深度的起始点需要是叶子节点

    int minDepth(TreeNode* root) {
        if(root==NULL)return 0;
        if(root->left==NULL)return minDepth(root->right)+1;
        if(root->right==NULL)return minDepth(root->left)+1;
        return min(minDepth(root->left),minDepth(root->right))+1;
    }

题解2 简化代码

    int minDepth(TreeNode* root) {
        if(root==NULL)return 0;
        if(root->left==NULL||root->right==NULL)
        return max(minDepth(root->left),minDepth(root->right))+1;
        return min(minDepth(root->left),minDepth(root->right))+1;
    }

题解3

    int minDepth(TreeNode* root) {
        if (!root) return 0;  //递归结束
        int left = minDepth(root->left);  
        int right = minDepth(root->right);
        if (!left || !right) return left + right + 1;  //如果有一个空,则+1
        return min(left, right) + 1;  //否则最小值+1
    }

简单的二叉树递归问题

226. 翻转二叉树

题目描述

在这里插入图片描述

题解1 先交换左右节点的位置再反转节点

    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL)return NULL;
        swap(root->left,root->right);
        root->left=invertTree(root->left);
        root->right=invertTree(root->right);
        return root;
    }

题解2 先反转左右节点 再交换位置

    TreeNode* invertTree(TreeNode* root) {
        if(root==NULL)return NULL;
        
        invertTree(root->left);
        invertTree(root->right);
        swap(root->left,root->right);
        return root;
    }

100. 相同的树

题目描述

在这里插入图片描述

题解1 判断左右节点是否相同并且root值相同

    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p==NULL)return q==NULL;
        else if(q==NULL)return false;
        else{
            return (isSameTree(p->left,q->left)&&isSameTree(p->right,q->right)&&p->val==q->val);
        }
        
    }

题解2 化简代码

    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(!p&&!q)return true;
        if(!p||!q)return false;//有一个节点为空提前返回
            return (isSameTree(p->left,q->left)&&isSameTree(p->right,q->right)&&p->val==q->val);
    }

101. 对称二叉树

题目描述

在这里插入图片描述

题解1 左子树反转后和右子树相同

class Solution {
public:
    TreeNode* reverse(TreeNode* root)//子树反转
    {
        if(root==NULL)return NULL;
        swap(root->left,root->right);
        reverse(root->left);
        reverse(root->right);
        return root;
    }
    bool issame(TreeNode* root1,TreeNode* root2)//判断是否相同
    {
        if(!root1&&!root2)return true;
        if(!root1||!root2)return false;
        return(issame(root1->left,root2->left)&&issame(root1->right,root2->right)&&root1->val==root2->val);
    }
    bool isSymmetric(TreeNode* root) {//反转后相同g
        if(root==NULL) return true;
        reverse(root->left);
        return(issame(root->left,root->right));
    }
};

题解2 右子树等于左子树 左子树等于右子树 根节点值相等

      bool dfs(TreeNode* root1,TreeNode* root2)
    {
        //if(!root1&&!root2)return true;
        if(!root1||!root2)return !root1&&!root2;
        return root1->val!=root2->val?false:dfs(root1->left,root2->right)&&dfs(root1->right,root2->left);
    }
    bool isSymmetric(TreeNode* root) {//反转后相同g
        //if(root==NULL) return true;
        return root?dfs(root->right,root->left):true;
    }

222. 完全二叉树的节点个数

题目描述

在这里插入图片描述

题解1 计算每个节点的个数(没有用的完全二叉树的性质)

    int countNodes1(TreeNode* root) {
        //if()return 0;
        return root == NULL ? 0 : 1 + countNodes1(root->left) + countNodes1(root->right);
    }

题解2 计算二叉树的层数

    int countlevel(TreeNode* root)
    {
        int ret=0;
        while(root)
        {
            ret++;
            root=root->left;
        }
        return ret;
    }
    int countNodes2(TreeNode* root) {
        if(root==NULL)return 0;
        int llevel=countlevel(root->left);
        int rlevel=countlevel(root->right);
        if(llevel==rlevel)//如果有左子树和右子树 右子树的节点数+完全的左子树的节点
        {
            return countNodes2(root->right)+(1<<llevel);//位运算简化
        }
        return countNodes2(root->left)+countNodes2(root->right)+1;
    }

题解3 二分查找

    bool judge(TreeNode* node, int h){//计算高度
        while(node){
            h--;
            node = node->left;
        }
        return h == 0;
    }

    int countNodes(TreeNode* root) {
        if(NULL == root) return 0;
        TreeNode* node = root;
        int h = 0;//树的高度
        while(node){
            h++;
            node = node->left;
        }
        
        node   = root;
        int sum = 1 << (h - 1);//满节点的数量
        while((--h) > 0){
            TreeNode* right = node->right;
            if(judge(right, h))//判断右子树最大 如果和h相同
            {
                sum += 1 << (h - 1);//左子树是满的
                node = node->right;
            }else{//和h高度不同 
                node = node->left;//说明左子树不满
            }
        };
        return sum;
    }

110. 平衡二叉树

题目描述

在这里插入图片描述

题解1

    int bfs(TreeNode* node)//-1表示不是平衡二叉树
    {
        if(node==NULL)return 0;
        int lbfs=bfs(node->left);
        if(lbfs==-1)return -1;//左右子树有一个不是 就提前终止
        int rbfs=bfs(node->right);
        if(rbfs==-1)return -1;
        
        return abs(lbfs-rbfs)<2? max(lbfs,rbfs)+1:-1;//看高度差

    }
    bool isBalanced(TreeNode* root) {
        return bfs(root)!=-1;
    }

题解2

     int countlevel(TreeNode* root)
    {
        if(root==NULL)return 0;
        return max(countlevel(root->left),countlevel(root->right))+1;
    }
    bool isBalanced(TreeNode* root) {
        if(root==NULL)return true;
        if(!isBalanced(root->left)||!isBalanced(root->right))return false;
        int llevel=countlevel(root->left);
        int rlevel=countlevel(root->right);
        return abs(llevel-rlevel)<2;
    }

题解3 优化 提前返回

    int countlevel(TreeNode* root)
    {
        if(root==NULL)return 0;
        return max(countlevel(root->left),countlevel(root->right))+1;
    }
    bool isBalanced(TreeNode* root) {//优化 提前返回
        if(root==NULL)return true;
        if(!(isBalanced(root->left)&&isBalanced(root->right)))return false;
        int llevel=countlevel(root->left);
        int rlevel=countlevel(root->right);
        return abs(llevel-rlevel)<2;
    }

注意递归的终止条件

112. 路径总和

题目描述

在这里插入图片描述

题解 看左节点有没有sum-val的路径

    bool hasPathSum(TreeNode* root, int sum) {
        if(root==NULL)return sum==0;
        return hasPathSum(root->left,sum-root->val)||hasPathSum(root->right,sum-root->val);
    }

404. 左叶子之和

题目描述

在这里插入图片描述

题解

如果是有左子树是左子叶 当前节点左子树值 +递归右子树
否则 左子叶的数量+右子叶的数量

    int sumOfLeftLeaves(TreeNode* root) {
        if(root==NULL)return 0;
        if(root->left&&root->left->left==NULL&&root->left->right==NULL)return sumOfLeftLeaves(root->right)+root->left->val;
        return sumOfLeftLeaves(root->left)+sumOfLeftLeaves(root->right);
    }

定义递归问题

257. 二叉树的所有路径

题目描述

在这里插入图片描述

题解1 终止条件 必须是叶子节点

    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> ret;
        if(root==NULL) return ret;
        if(root->left==NULL&&root->right==NULL)//是叶子节点
        {
            ret.push_back(to_string(root->val));//结尾放当前节点
            return ret;
        }
        vector<string> lret=binaryTreePaths(root->left);//左子叶的路径
        for(int i=0;i<lret.size();i++)
        {
            ret.push_back(to_string(root->val)+"->"+lret[i]);
        }
        vector<string> rret=binaryTreePaths(root->right);//右子叶的路径
        for(int i=0;i<rret.size();i++)
        {
            ret.push_back(to_string(root->val)+"->"+rret[i]);
        }
        return ret;
    }

题解2

class Solution {
public:
    void dfs(TreeNode* root,vector<string>& ret)
    {
        if(root==NULL)return;
        if(root->left==NULL&&root->right==NULL)//是叶子节点
        {
            ret.back()+=to_string(root->val);
            return;
        }
        if(root->left&&root->right)//都有
        {
            string tmp=ret.back();//加入当前节点 再遍历左子树
            ret.back()+=to_string(root->val)+"->";
            dfs(root->left,ret);

            ret.push_back(tmp);//加上当前节点 遍历右子树
            ret.back()+=to_string(root->val)+"->";
            dfs(root->right,ret);
            return;
        }
        if(root->left)
        {
            ret.back()+=to_string(root->val)+"->";
            dfs(root->left,ret);
            return;
        }
        ret.back()+=to_string(root->val)+"->";
        dfs(root->right,ret);
        return;
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        
        vector<string> ret;
        if(root==NULL)return ret;
        ret.push_back(string());//把结果传进来
        dfs(root,ret);
        return ret;
    }
};

题解3 使用栈

    vector<string> binaryTreePaths(TreeNode* root) {  
        vector<string> ret;
        if(root==NULL)return ret;
        stack<pair<TreeNode*,string>> s;//当前节点以及到当前节点的路径
        pair<TreeNode*,string> tmp;//临时变量
        s.push(make_pair(root,to_string(root->val)));
        while(!s.empty())
        {
            tmp=s.top();
            s.pop();
            if(tmp.first->right)//有右子树
            {
                s.push(make_pair(tmp.first->right,tmp.second+"->"+to_string(tmp.first->right->val)));//添加子树元素
            }
            if(tmp.first->left)//有左子树
            {
                s.push(make_pair(tmp.first->left,tmp.second+"->"+to_string(tmp.first->left->val)));//添加子叶元素
            }
            if(!tmp.first->right&&!tmp.first->left)//是叶子节点
            {
                ret.push_back(tmp.second);//在返回值添加
            }
        
        }
        return ret;
    }  

113. 路径总和 II

题目描述

在这里插入图片描述

方法1 递归

public:
    void dfs(TreeNode* root,vector<vector<int>>&ret,vector<int>tmpret,int sum)
    {
        if(root==NULL)return;
        if(!root->left&&!root->right&&sum==root->val)//是子叶节点并且值相等
        {
            tmpret.push_back(root->val);
            ret.push_back(tmpret);//添加子路径
        }
        tmpret.push_back(root->val);//添加当前节点值
        dfs(root->left,ret,tmpret,sum-root->val);
        dfs(root->right,ret,tmpret,sum-root->val);
        return;
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>>ret;
        vector<int> tmpret;
        dfs(root,ret,tmpret,sum);
        
        return ret;
    }

};

方法2 用栈模仿递归

   vector<vector<int>> res;
    vector<int> temp;//防止反复初始化数组 
    void dfs(TreeNode* root,int sum){
        int resum=sum-root->val;//要找的值
        temp.push_back(root->val);//假设它在
        if(resum==0&&!root->left&&!root->right)
			res.push_back(temp);//找到答案 
        if(root->left)
			dfs(root->left,resum);
        if(root->right)
			dfs(root->right,resum);
        temp.pop_back();//回溯  temp是全局变量
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        if(root)dfs(root,sum);
        return res;
    }

129. 求根到叶子节点数字之和

题目描述

在这里插入图片描述

题解

    int sum=0;//返回值
    int tmpsum=0;//临时的值
    int sumNumbers(TreeNode* root) {
        if(root==NULL) return 0;
        int t=tmpsum;//之前的累加
        tmpsum=tmpsum*10+root->val;//加上该节点
        if(!root->left&&!root->right)sum+=tmpsum;//叶子节点就在返回值上加
        sumNumbers(root->left);
        sumNumbers(root->right);
        tmpsum=t;
        return sum;
    }

复杂的二叉树递归问题

437. 路径总和 III

题目描述

在这里插入图片描述

题解 分为包含当前节点和不包含当前节点 两种递归情况

    int pathSum(TreeNode* root, int sum) {
        if(root==NULL)return NULL;
        int ret=0;
        ret+=findpath(root,sum);
        ret+=pathSum(root->left,sum);
        ret+=pathSum(root->right,sum);
        return ret;
    }
    int findpath(TreeNode* root,int sum)//包含当前节点
    {
        if(root==NULL)return 0;
        int ret=0;
        if(root->val==sum)ret=1;
        ret+=(findpath(root->left,sum-root->val)+findpath(root->right,sum-root->val));//可能为负数
        return ret;
    }

二分搜索树问题

530. 二叉搜索树的最小绝对差

题目描述

在这里插入图片描述

题解1 二叉树中序遍历 利用栈模拟实现

题解2 递归实现二叉树中序遍历 储存上一个节点

    void getMinimum(TreeNode* root,int &pre,int& minval) {//储存上一个节点的值
        if(root==NULL)
        { 
            return ;
        }
	  getMinimum(root->left,pre,minval);//传地址
        if(pre>=0){minval=min(root->val-pre,minval);}
        pre=root->val;

        getMinimum(root->right,pre,minval);
        return;
        
    }
    int getMinimumDifference(TreeNode* root) {
        if(root==NULL)
        {
            return 0;
        }
        int pre=-1;
        int minval=INT_MAX;
        getMinimum(root,pre,minval);
        return minval;
    }

235. 二叉搜索树的最近公共祖先

题目描述

在这里插入图片描述

题解1 根据二叉搜索树的性质判断

public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL)return NULL;
        if(p->val>root->val&&q->val>root->val)//都小在右子树中找
        return lowestCommonAncestor(root->right,p,q);
        if(p->val<root->val&&q->val<root->val)//都大在左子树中找
        return lowestCommonAncestor(root->left,p,q);
        return root;//如果一大一小 或者有节点相等 那么当前节点就是公共祖先
    }

98. 验证二叉搜索树

题目描述

在这里插入图片描述

题解1 利用中序遍历从小到大的性质

    bool ValidBST(TreeNode* root,long long &min) {//上一个节点的值
        if(root==NULL)return true;
        
        if(!ValidBST(root->left,min))return false;
        if(root->val<=min)return false;//当前节点的值大于等于上一个节点的值就不是搜索树
        min=root->val;
        return ValidBST(root->right,min);

    }
    bool isValidBST(TreeNode* root) {
        if(root==NULL)return true;
        long long min=LONG_MIN;
        return ValidBST(root,min);
    }

题解2 根据定义进行判断

    bool ValidBST(TreeNode* root,long long min,long long  max) {
        if(root==NULL)return true;
        if(root->val<=min||root->val>=max)
            return false;
        return ValidBST(root->left,min,root->val)&&ValidBST(root->right,root->val,max);//左边是搜索树右边也是搜索树
    }
    bool isValidBST(TreeNode* root) {
        if(root==NULL)return true;
        return ValidBST(root,LONG_MIN,LONG_MAX);
    }

题解3 利用栈进行中序遍历

    bool isValidBST(TreeNode* root) {
        if(root==NULL)return true;
        long long min=LONG_MIN;
        stack<TreeNode*> s;
       // s.push(root);
        while(!s.empty()||root)
        {
            while(root)
            {               
                s.push(root);
                root=root->left;
            }
            root=s.top();
            s.pop();
            if(root->val<=min)return false;
            min=root->val;
            root=root->right;
        }
        return true;
    }

450. 删除二叉搜索树中的节点

题目描述

在这里插入图片描述

思路1 找到右子树中的最小值替换当前节点

    TreeNode* findmin(TreeNode* node)//右子树的最小值
    {
        while(node->left)
        {
            node=node->left;
        }
        return node;
    }
    TreeNode* deleteNode(TreeNode* node, int key) {
        if(node==NULL)return NULL;
        if(node->val>key)//在左子树中找
            node->left=deleteNode(node->left,key);
        else if(node->val<key)
            node->right=deleteNode(node->right,key);
        else//删除当前节点
        {
        if(!node->left&&!node->right) {delete node; return NULL;}
        if(!node->right)//没有右子树 说明是最大值
        {
            TreeNode* tmp=node->left;
            delete node;
            return tmp;
        }
        else if(!node->left)//没有左子树 说明是最小值
        {
            TreeNode* tmp=node->right;
            delete node;
            return tmp;
        }
        else
        {
            TreeNode* tmp=findmin(node->right);//右子树的最小值
            cout<<tmp->val;
            swap(node->val,tmp->val);//交换
            node->right=deleteNode(node->right,key);//递归删除
            return node;
        }
        }
         return node;
    }

108. 将有序数组转换为二叉搜索树

题目描述

在这里插入图片描述

题解1 通过对数组的二分查找将根节点设置为中间值

    TreeNode*sorted(vector<int>&nums,int l,int r)
    {
        
        if(l>r)return NULL;
        //if(l==r) return new TreeNode(nums[l]);
        int mid=l+(r-l)/2;
       
        TreeNode* root=new TreeNode(nums[mid]);
        root->left=sorted(nums,l,mid-1);
        root->right=sorted(nums,mid+1,r);
        return root;
    }
    TreeNode* sortedArrayToBST(vector<int>& nums) {

        return sorted(nums,0,nums.size()-1);
    }

230. 二叉搜索树中第K小的元素

题目描述

题解1 统计左右子树节点个数

    int numroot(TreeNode* root)
    {
        if(root==NULL)return 0;
        return 1+numroot(root->left)+numroot(root->right);
    }
    int kthSmallest(TreeNode* root, int k) {
        if(root==NULL)return 0;
        int num=numroot(root->left);//左子树节点个数
        if(num==k-1)return root->val;
        if(num>=k) return kthSmallest(root->left,k);
        else
        return kthSmallest(root->right,k-num-1);
    }

利用栈中序遍历 记录当前节点是第几个节点

    int kthSmallest(TreeNode* root, int k) {
        stack<TreeNode*> s;
        int ret;
        if(root==NULL)return 0;
        int i=0;
        TreeNode* tmp;
        while(!s.empty()||root)
        {
            while(root)
            {
                s.push(root);
                root=root->left;
            }
             tmp=s.top();
            s.pop();
            i++;
            if(i==k)break;
            root=tmp->right;
        }
        return tmp->val;
    }

思路3 递归中序遍历二叉树

    void numroot(TreeNode* root,int k,int &pre)
    {
        if(root==NULL)return ;
        numroot(root->left,k,pre);
        i++;
        if(i==k)
        {pre=root->val;return;}
        
        numroot(root->right,k,pre);
        return ;
    }
    int kthSmallest(TreeNode* root,int k) {
        if(root==NULL)return 0;
        int pre=-1;
        numroot(root,k,pre);//pre为返回值 找到的二叉树节点的值
        return pre;
    }

思路4 取消传出参数 之间返回

    int kthSmallest(TreeNode* root,int k) {
       
        if(root==NULL)return 0;

        int ret=kthSmallest(root->left,k);
        if (ret!=0)return ret;
        i++;
        if(i==k)
        {return root->val;}
        
        return kthSmallest(root->right,k);
    
    }

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

题目描述

在这里插入图片描述

题解1 递归遍历二叉树

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL)
        return NULL;
        if(root->val==p->val||root->val==q->val)
        return root;
        
        TreeNode* ltree=lowestCommonAncestor(root->left,p,q);//查看左子树中有没有p或q
        //if(ltree)cout<<"lroot"<<ltree->val<<endl;
        TreeNode* rtree=lowestCommonAncestor(root->right,p,q);//查看右子树中给有没有p或q
        if(ltree==NULL)return rtree;//左子树中没有 就在右子树中
        if(rtree==NULL)return ltree;//右子树中没有 就在左子树中
        if(ltree&&rtree)return root;//如果都有 说明一边一个
        return NULL;
        }

题解2

class Solution {
public:    
    unordered_map<int,TreeNode*> father;//记每个节点的父节点
    unordered_map<int,bool> visited;//从p到根节点的路径
    void dfs(TreeNode* root)//记录每个节点的父节点
    {
        if (root==NULL)return;
        if(root->left)
        {
            father[root->left->val]=root;
            dfs(root->left);
        }
        if(root->right)
        {
            father[root->right->val]=root;
            dfs(root->right);
        }
        return;
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        father[root->val]=NULL;
        dfs(root);
        while(p)
        {
            visited[p->val]=true;//从p开始遍历 标记p所有的父节点
            cout<<p->val<<endl;
            p=father[p->val];
        }
        while(q)
        {
            if(visited[q->val])break;//找到父节点
            q=father[q->val]; 
        }
        return q;
    }
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值