代码随想录算法训练营第十一天--二叉树2 || 226.翻转二叉树 / 101.对称二叉树 / 104.二叉树的最大深度 / 111.二叉树的最小深度

发布于:2025-09-15 ⋅ 阅读:(27) ⋅ 点赞:(0)

226.翻转二叉树(优先掌握递归)

解题思路

在这里插入图片描述
我们要翻转的不只是数字,而是指针。

递归法

/**
 * 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) {
        if(root == NULL) return root;
        swap(root -> left, root -> right); // 中
        invertTree(root -> left); // 左
        invertTree(root -> right); // 右
        return root;
    }
};

上述代码使用的前序遍历法,当然也可以使用后序遍历法,但是**不能使用中序遍历法。
因为我们先翻转左子树,然后翻转中间节点,原来翻转过来的左子树翻转到右侧,我们又一次翻转右子树,那么把原来翻转过来的左子树又翻转回去了。而原来右子树没有进行翻转。
中序遍历代码如下:

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == NULL) return root;
        invertTree(root -> left); // 左
        swap(root -> left, root -> right); // 中
        invertTree(root -> left); // 右
        return root;
    }
};

迭代法 – 深度优先遍历

我们采用前序遍历

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        stack<TreeNode*> st;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top(); // 中
            st.pop();
            swap(node -> left, node -> right);
            if (node -> right) st.push(node -> right); // 右
            if (node -> left) st.push(node -> 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:
    TreeNode* invertTree(TreeNode* root) {
        stack<TreeNode*> st;
        if (root != NULL) st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
                if (node -> right) st.push(node -> right); // 右
                if (node -> left) st.push(node -> left); // 左
                st.push(node); // 中
                st.push(NULL);
            } else {
                st.pop();
                node = st.top();
                st.pop();
                swap(node -> left, node -> right);
            }
        }
        return root;
    }
};

层序遍历 – 广度优先搜索

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        while (!que.empty()) {
            int size = que.size();
            while (size --) {
                TreeNode* node = que.front(); // 中
                que.pop();
                swap(node -> left, node -> right); // 节点处理
                if (node -> left) que.push(node -> left); // 左
                if (node -> right) que.push(node -> right); // 右
            }
        }
        return root;
    }
};

101.对称二叉树(优先掌握递归)

解题思路

对于要搜集左右孩子,返回到中间节点的情况,我们一般采取后序遍历,这个非常重要。
在这里插入图片描述
这道题的关键是要判断外侧相等,里侧相等,比较根节点的左右两棵子树能否互相翻转。

递归法

递归三部曲
1.先判断返回值和传入的参数:
返回bool类型,参数就是左右节点

2.确定终止条件:

  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return false
  • 左右都为空,对称,返回true
  • 左右都不为空,左右值不同,return false
  • 左右都不为空,左右值相同,进入单层递归

3.确定单层递归逻辑

  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。

完整代码

/**
 * 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 compare(TreeNode* left, TreeNode* right) {
        // 分五种情况
        if (left == NULL && right != NULL) return false; // 1.左空,右非空
        else if (left != NULL && right == NULL) return false; // 2.左非空,右空
        else if (left == NULL && right == NULL) return true; // 3.左空,右空
        else if (left -> val != right -> val) return false; // 4.左值 不等于 右值
        // 5.左值 = 右值
        bool outside = compare(left -> left, right -> right); // 左子树:左  右子树:右
        bool inside = compare(left -> right, right -> left); // 右    左
        bool issame = outside && inside; // 中    中
        return issame;
    }
    bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        return compare(root -> left, root -> right);
    }
};

迭代法

使用队列

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        queue<TreeNode*> que;
        que.push(root -> left); // 将左子树头节点入队
        que.push(root -> right); // 将右子树头节点入队

        while (!que.empty()) { // 判断两个树是否相互翻转
            TreeNode* l = que.front(); que.pop();
            TreeNode* r = que.front(); que.pop();
            
            // 左右皆空,对称
            if (l == NULL && r == NULL) continue;

            // 左右一个为空 or 都不空但值不相等,不对称
            if (l == NULL || r == NULL || l -> val != r -> val)
                return false;

            que.push(l -> left); // 左节点左孩子
            que.push(r -> right); // 右节点右孩子
            que.push(l -> right); // 左节点右孩子
            que.push(r -> left); // 右节点左孩子
        }
        return true;
    }
};

练习1

100.相同的树

class Solution {
public:
    bool cmp(TreeNode* p, TreeNode* q) {
        if (p == NULL && q == NULL) return true;
        else if (p == NULL || q == NULL || p -> val != q -> val) return false;
        bool isl = cmp(p -> left, q -> left);
        bool isr = cmp(p -> right, q -> right);
        return isl && isr;
    }
    bool isSameTree(TreeNode* p, TreeNode* q) {
        return cmp(p, q);
    }
};

练习2:

572.另一棵树的子树

class Solution {
public:
    bool cmp(TreeNode* root, TreeNode* subRoot) {
        if (root == NULL && subRoot == NULL) return true;
        else if (root == NULL || subRoot == NULL || root -> val != subRoot -> val)
            return false;
        bool isl = cmp(root -> left, subRoot -> left);
        bool isr = cmp(root -> right, subRoot -> right);
        return isl && isr;
    }
    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        if (root == NULL) return false;
        return cmp(root, subRoot) ||
            isSubtree(root -> left, subRoot) ||
            isSubtree(root -> right, subRoot);
    }
};

这道题首先要判断根节点非空,防止对空节点进行操作。
然后我们就像100.相同的树一样去比较是否相等,不相等我们就递归isSubtree函数,直到找到相等的子树。

104.二叉树的最大深度

递归法

我们要分清高度深度的概念,对于一个二叉树,最上面的根节点的深度为1,高度就是深度的最大值,也就是说高度和深度是反转关系的。
一般使用后序遍历来求二叉树的最大高度,也就是二叉树的最大深度

public:
    int getDepth(TreeNode* node) {
        if (node == NULL) return 0; // 终止条件,最底层的下一层高度为0
        int leftDepth = getDepth(node -> left); // 左
        int rightDepth = getDepth(node -> right); // 右
        int depth = 1 + max(leftDepth, rightDepth); // 中
        return depth;
    }
    int maxDepth(TreeNode* root) {
        return getDepth(root);
    }
};

代码可以精简

class Solution {
public:
    int getDepth(TreeNode* node) {
        if (node == NULL) return 0; // 终止条件,最底层的下一层高度为0
        return 1 + max(getDepth(node -> left), getDepth(node -> right));
    }
    int maxDepth(TreeNode* root) {
        return getDepth(root);
    }
};

层序遍历–迭代法

class Solution {
public:
    int maxDepth(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        int depth = 0;
        while (!que.empty()) {
            int size = que.size();
            depth ++; // 记录深度
            while (size --) {
                TreeNode* node = que.front();
                que.pop();
                if (node -> left) que.push(node -> left);
                if (node -> right) que.push(node -> right);
            }
        }
        return ans;
    }
};

练习:

559.N叉树的最大深度

迭代法–层序遍历

class Solution {
public:
    int maxDepth(Node* root) {
        queue<Node*> que;
        if (root != NULL) que.push(root);
        int depth = 0;
        while (!que.empty()) {
            int size = que.size();
            depth ++;

            while (size --) {
                Node* node = que.front();
                que.pop();
                for (int i = 0; i < node -> children.size(); i++) {
                    if (node -> children[i]) que.push(node -> children[i]);
                }
            }
        }
        return depth;
    }
};

递归法

class Solution {
public:
    int getDepth(Node* node) {
        if (node == NULL) return 0;
        int depth = 0;
        for (int i = 0; i < node -> children.size(); i++) {
            depth = max(depth, getDepth(node -> children[i]));
        }
        return depth + 1;
    }
    int maxDepth(Node* root) {
        return getDepth(root);
    }
};

最后为什么要加1呢,想想之前的二叉树,是左右,然后中,中是1 + max(左,右)。这里for循环就先当于左右,最后到中需要加1。

111.二叉树的最小深度

审题

这道题的最小深度,指的是叶子节点是指没有子节点的节点,有一个节点的,不叫最小深度,必须左右两个节点都无才算。
在这里插入图片描述

递归法

class Solution {
public:
    int getDepth(TreeNode* node) {
        int res = 0;
        if (node == NULL) return 0;
        int left = getDepth(node -> left);      // 左
        int right = getDepth(node -> right);    // 右
                                                // 中
        // 当一个左子树为空,右不为空,这时并不是最低点
        // 当一个右子树为空,左不为空,这时并不是最低点
        if (node -> left == NULL && node -> right != NULL) {
            res = 1 + right;
        } else if (node -> left != NULL && node -> right == NULL) {
            res = 1 + left;
        } else {
            res = 1 + min(left, right);
        }
        return res;
    }
    int minDepth(TreeNode* root) {
        return getDepth(root);
    }
};

迭代法–层序遍历

class Solution {
public:
    int minDepth(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        int depth = 0;
        while (!que.empty()) {
            int size = que.size();
            depth ++;
            while (size --) {
                TreeNode* node = que.front();
                que.pop();
                if (node -> left) que.push(node -> left);
                if (node -> right) que.push(node -> right);
                if (!node -> left && !node -> right) return depth;
            }
        }
        return depth;
    }
};

注意一下depth的位置,层序遍历是从上到下遍历,当左右无节点,那就直接返回。


网站公告

今日签到

点亮在社区的每一天
去签到