算法第12天|继续学习二叉树:翻转二叉树、对称二叉树、二叉树最大深度、二叉树的最小深度

发布于:2025-06-11 ⋅ 阅读:(27) ⋅ 点赞:(0)

今日总结:

        递归法的三段式应用

                1、确定递归的返回参数、输入参数

                2、确定递归的停止条件

                3、确定单次递归的递归逻辑与返回值

        对称二叉树需要重新思考

                1、迭代法中是如何使用队列进行判断对称的

                2、递归法中是传入什么参数,什么逻辑判断对称的

        二叉树的最小深度需要重新思考:

                所谓的深度是指根节点到叶子节点,如果某个节点只有左子节点或者右子节点,不是最短的路径,只有左右子节点都没有的时候才是底。

翻转二叉树

题目链接:226. 翻转二叉树 - 力扣(LeetCode)

整体思路:

        翻转二叉树,本质上可以看作是对左右子树的翻转,所以更加细的讲:将每个节点的左右子节点进行翻转就实现了翻转二叉树。

        对于深度优先搜索:

                前序遍历(中前后)(递归、迭代)

                后序遍历(前后中)(递归、迭代)

        对于广度优先搜索:
               
层序遍历(递归、迭代)

        都是可以使用的,在要将当前位置节点记录的时候转换左右节点就实现了翻转二叉树。

        前序遍历递归翻转二叉树代码


/**
 * 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:
//前序遍历
    void digui(TreeNode* &root)
    {
        //判断停止条件
        if(root==nullptr)return;
        swap(root->left,root->right);
        digui(root->left);
        digui(root->right);
    }
    TreeNode* invertTree(TreeNode* root) {
        //深度优先、前序遍历翻转
        digui(root);
        return root;
    }
};

        前序遍历迭代翻转二叉树代码

/**
 * 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:
    TreeNode* invertTree(TreeNode* root) {
        深度优先、前序遍历迭代法
        stack<TreeNode*>stk;
        //根节点入栈
        if(root==nullptr)return root;
        stk.push(root);
        while(!stk.empty())
        {
            //出栈
            TreeNode*cur = stk.top();
            stk.pop();
            swap(cur->left,cur->right);
            //右左节点入栈
            if(cur->right!=nullptr)stk.push(cur->right);
            if(cur->left!=nullptr)stk.push(cur->left);
        }
        return root;
    }
};

        层序遍历递归翻转二叉树代码

/**
 * 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<vector<int>>res;
    void digui(TreeNode* &root,int depth)
    {
        //停止条件
        if(root==nullptr)return ;
        //判断是不是第一次进入这一行
        if(res.size()==depth)res.push_back(vector<int>());
        res[depth].push_back(root->val);
        //交换左右子节点
        swap(root->left,root->right);
        if(root->left!=nullptr) digui(root->left,depth+1);
        if(root->right!=nullptr) digui(root->right,depth+1);
        //递归左,递归右
    }
    TreeNode* invertTree(TreeNode* root) {
        //使用广度优先,层序遍历,递归法
        //定义一个存储节点的vector数组,因为要跟depth比较
        digui(root,0);
        return root;        
        
    }
};

        层序遍历迭代翻转二叉树代码

/**
 * 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:
    TreeNode* invertTree(TreeNode* root) {

        //使用广度优先、层序遍历迭代法
        //定义队列
        queue <TreeNode*>que;
        if(root==nullptr)return root;
        que.push(root);
        //开始while判断
        while(!que.empty())
        {
            //记录队列的长度,因为队列一直变换
            int size = que.size();
            for(int i=0;i<size;i++)
            {
                //弹出队头
                TreeNode* cur = que.front();
                que.pop();
                swap(cur->left,cur->right);
                if(cur->left!=nullptr) que.push(cur->left);
                if(cur->right!=nullptr)que.push(cur->right);
            }
        }
        return root;
        
    }
};

对称二叉树

题目链接:101. 对称二叉树 - 力扣(LeetCode)

整体思路:

        因为是寻找对称,是左边与右边的关系,可以看作是两棵子树的关系,可以通过对左右两棵子树的对应位置进行判断:使用递归、迭代(两个对应节点一组入栈或队)

        递归法:

        1、确定返回参数、传入的参数

                这个题是判断是不是对称,返回参数是bool;

                这个题是判断左右子树是不是对称,传入参数是两个节点

bool digui(TreeNode* left,TreeNode* right)

        2、确定停止条件

                因为是判断是不是对称,当出现不对称或者遍历完了就返回

                左边空,右边不空,返回false

                左边不空,右边空,返回false

                左边空,右边空,返回true

                左边不空,右边不空,左边值不等于右边值,返回false 

if(left==nullptr&&right!=nullptr) return false;
else if(left!=nullptr&&right==nullptr) return false;
else if(left!=nullptr&&right!=nullptr&&left->val!=right->val)return false;
else if(left==nullptr&&right ==nullptr)return true;

        3、确定单次递归的逻辑

                获取下一次递归返回的bool值进行判断当前层次返回值

                (1)将左节点的左节点与右节点的右节点继续递归

                (2)将左节点的右节点与右节点的左节点继续递归

                (3)两者的返回值都是true,当前层的返回值才能是true;

        递归法代码

// /**
//  * 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 digui(TreeNode* left,TreeNode* right)
    {
        //设置停止条件
        //如果左空右不空、左不空右空、左右都不空但是值不同、左右都空
        if(left==nullptr&&right!=nullptr) return false;
        else if(left!=nullptr&&right==nullptr) return false;
        else if(left!=nullptr&&right!=nullptr&&left->val!=right->val)return false;
        else if(left==nullptr&&right ==nullptr)return true;
        //只剩下左右都不空左右值相同
        //左右两个节点都有自己的左右节点,所以是左节点的左子节点与右节点的右子节点;左节点的右子节点与右节点的左子节点进行判断
        bool A = digui(left->left,right->right);
        bool B = digui(left->right, right->left);
        bool C =false;
        return C= A&&B;

    }

    bool isSymmetric(TreeNode* root) {
        //轴对称、首先判断左子节点与右子节点,之后判断的是左子节点的左子节点与右子节点的右子节点
        //使用一个递归形式,将整个二叉树分为左子树与右子树
        if(root==nullptr)return true;
        return digui(root->left, root->right);
        
        
   

         迭代法:

                迭代法类似于层序遍历,但是与层序遍历不同;

                (1)设置一个队列,用于存储左右子树的对应节点,

                (2)每次取出对应的两个节点,用于判断当前两个节点是不是相同(对称)

                (3)之后将两个节点的对应子节点入队,直到队空

        迭代法代码
/**
 * 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 isSymmetric(TreeNode* root) {
        //使用类似层序遍历,队列
        //将一层的节点输入进队列,两个两个的拿出,然后将其子节点输入到队列,直到队列为空
        queue <TreeNode*> que;
        if(root==nullptr)return true;
        //将根节点的左右子节点输入到队列
        que.push(root->left);
        que.push(root->right);
        while(!que.empty())
        {
            //进行判断两个节点的关系,出队
            TreeNode* cur1 = que.front();
            que.pop();
            TreeNode* cur2 =que.front();
            que.pop();
            if(cur1==nullptr&&cur2!=nullptr)return false;
            else if(cur1!=nullptr&&cur2==nullptr)return false;
            else if(cur1==nullptr&&cur2==nullptr) continue;//不能直接返回true,因为跟递归不同,返回true不是返回上一层,而是直接返回答案,应该用continue直到队列是空的
            else if(cur1!=nullptr&&cur2!=nullptr&&cur1->val!=cur2->val)return false;
            //此时只有两个节点不空、节点一样
            //队列中加入两个节点的对应位置的子节点
            que.push(cur1->left);
            que.push(cur2->right);
            que.push(cur1->right);
            que.push(cur2->left);
        }
        return true;

        
    }
};

二叉树的最大深度

整体思路

        二叉树的深度,就是根节点到叶子节点的最远距离,可以使用递归的形式,从最下边开始计算节点的高度,直到根节点;也可以使用迭代法层序遍历直接判断有多少层

        递归法

                1、确定递归返回参数、输入参数

                        递归的返回参数应该是当前节点的高度,输入参数应该是当前节点

                2、确定递归停止条件

                        当节点与到nullptr表示找到了叶子节点的下一个子节点,所以此层的高度应该是0

                3、确定单层递归的递归逻辑

                        一个节点有左右子节点,当前节点返回:获取左右子节点的最大高度后+1

        递归法代码
/**
 * 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:
    //1、确定递归返回参数、输入参数
    //返回参数应该是高度,输入的参数应该是节点
    int getdepth(TreeNode*root)
    {
        //2、确定停止条件
        //当前节点是nullptr的时候就返回,返回的是高度0,假设叶子节点是高度1
        if(root==nullptr)return 0;
        //3、确定单层循环的循环逻辑
        //获取左右子节点的高度,返回高的那个
        int depth_left = getdepth(root->left);
        int depth_right =getdepth(root->right);
        return 1+max(depth_left,depth_right);
    }
    int maxDepth(TreeNode* root) {
        //使用递归的方法,进行寻找depth
        int depth = getdepth(root);
        return depth;

        
    }
};

        迭代法:

                层序遍历迭代法模板

/**
 * 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:
    int maxDepth(TreeNode* root) {
        //定义一个深度
        int depth=0;
        //定义一个队列
        queue <TreeNode*>que;
        //根节点
        if(root==nullptr)return 0;
        que.push(root);
        while(!que.empty())
        {
            //获取队列大小
            int size = que.size();
            for(int i=0;i<size;i++)
            {
                //临时节点,出队
                TreeNode* cur = que.front();
                que.pop();
                if(cur->left!=nullptr) que.push(cur->left);
                if(cur->right!=nullptr) que.push(cur->right);
            }
            depth++;
        }
        return depth;
    }
};

二叉树的最小深度

题目链接:111. 二叉树的最小深度 - 力扣(LeetCode)

整体思路:

        与二叉树的最大深度类似,但是不能直接修改为min,因为所谓的最小深度,是从叶子节点到根节点,如果一个节点只有一个子节点,不属于叶子节点:

        此时的最小深度应该需要是从拥有的子节点的那条路径进行往下,所以需要在最大深度的代码上添加限制条件:出现一个子节点的时候要如何?

        递归法:

/**
 * 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:
    //1、确定递归的返回、输入
    int getdepth(TreeNode* root)
    {
        //2、确定递归的停止
        if(root==nullptr)return 0;//最后的高度为0
        //3、确定单层的逻辑及返回值
        //如果当前节点的左右子节点不全,不能直接获取最小的depth,,而是让另一个不为nullptr的节点继续遍历,获取他的高度,只有叶子节点才能是底层的高度1
        int left_depth = getdepth(root->left);
        int right_depth = getdepth(root->right);
        if(root->left==nullptr&&root->right!=nullptr)
            return 1+right_depth;
        if(root->left!=nullptr&&root->right==nullptr)
            return 1+left_depth;
        


        int depth = 1+min(left_depth,right_depth);
        return depth;
    }
    int minDepth(TreeNode* root) {
        return getdepth(root);  
    }
};

        迭代法:       

                迭代法就是在层序遍历迭代法的模板上,添加限制条件:寻找最先遇到的叶节点(左右子节点都没有)

/**
 * 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:
    int minDepth(TreeNode* root) {
        //层序遍历迭代法:
        //定义队列,深度
        queue<TreeNode*>que;
        int depth=0;
        //根节点入队
        if(root==nullptr)return 0;
        que.push(root);
        while(!que.empty())
        {
            //定义队列大小
            int size = que.size();
            depth++;
            for(int i=0;i<size;i++)
            {
                TreeNode* cur =  que.front();
                que.pop();
                
                //如果当前节点没有子节点,就可以直接返回深度了
                if(cur->left==nullptr&&cur->right==nullptr)return depth;
                if(cur->left!=nullptr) que.push(cur->left);
                if(cur->right!=nullptr) que.push(cur->right);
            }
        }
        return depth;
        
    }
};


// /**
//  * 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:
//     //1、确定递归的返回、输入
//     int getdepth(TreeNode* root)
//     {
//         //2、确定递归的停止
//         if(root==nullptr)return 0;//最后的高度为0
//         //3、确定单层的逻辑及返回值
//         //如果当前节点的左右子节点不全,不能直接获取最小的depth,,而是让另一个不为nullptr的节点继续遍历,获取他的高度,只有叶子节点才能是底层的高度1
//         int left_depth = getdepth(root->left);
//         int right_depth = getdepth(root->right);
//         if(root->left==nullptr&&root->right!=nullptr)
//             return 1+right_depth;
//         if(root->left!=nullptr&&root->right==nullptr)
//             return 1+left_depth;
        


//         int depth = 1+min(left_depth,right_depth);
//         return depth;
//     }
//     int minDepth(TreeNode* root) {
//         return getdepth(root);  
//     }
// };