Leetcode算法训练日记 | day15

一、二叉树的层序遍历

1.题目

Leetcode:第 102 题

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

2.解题思路

递归法和迭代法

3.实现代码

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

// 定义一个结构体TreeNode,用于表示二叉树的节点。
struct TreeNode {
    int val; // 存储节点的值。
    TreeNode* left; // 指向该节点左子树的指针。
    TreeNode* right; // 指向该节点右子树的指针。
    // TreeNode的构造函数,用于创建一个TreeNode实例。
    // 参数x是节点的值,left和right默认为NULL,表示没有左右子节点。
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

//一、二叉树的层序遍历(递归法)
class Solution1 {
public:
    // 定义名为order的辅助函数,用于递归地进行层序遍历。
    // 该函数接受三个参数:当前节点指针cur,用于存储结果的二维向量引用result,以及当前的深度depth。
    void order(TreeNode* cur, vector<vector<int>>& result, int depth) {
    
        if (cur == NULL) {// 如果当前节点为空,则直接返回。
            return;
        }
        if (result.size() == depth) {// 如果容器result的大小等于当前深度depth,说明需要创建一个新的层级。
            result.push_back(vector<int>()); // 创建一个新的层级,即一个空的一维数组,并将其添加到result中。
        }
        
        result[depth].push_back(cur->val); // 将当前节点的值添加到对应层级的末尾。
        order(cur->left, result, depth + 1); // 递归地对当前节点的左子节点进行层序遍历,深度增加1。
        order(cur->right, result, depth + 1);// 递归地对当前节点的右子节点进行层序遍历,深度增加1。
        
    }
    // 定义名为levelOrder的公共成员函数,用于返回二叉树的层序遍历结果。
    // 函数接受一个参数:二叉树的根节点指针root。
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result; // 创建一个空的二维数组result,用于存储层序遍历的结果。
        int depth = 0; // 初始化深度为0,表示从根节点开始遍历。
        order(root, result, depth);// 调用辅助函数order,从根节点开始进行层序遍历,并将结果存储在result中。
        return result; // 返回包含层序遍历结果。
    }
};

//、二叉树的层序遍历(迭代法)
class Solution2 {
public:
    // 定义名为levelOrder的公共成员函数,用于返回二叉树的层序遍历结果。
    // 函数接受一个参数:二叉树的根节点指针root。
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;// 创建一个队列que,用于存储待访问的节点。
        if (root != NULL) { // 检查传入的二叉树根节点是否为空。
            que.push(root);// 如果根节点不为空,则将其入队。
        }
        vector<vector<int>> result;// 创建一个空的二维数组result,用于存储层序遍历的结果。
        while (!que.empty()) {  // 使用while循环进行遍历,直到队列为空。
            int size = que.size(); // 获取队列中的节点数量。
            vector<int> vec;// 创建一个一维数组vec,用于存储当前层的节点值。
            for (int i = 0; i < size; i++) {// 遍历当前层的所有节点。
                TreeNode* node = que.front(); // 取出队列前端的节点。
                que.pop();// 将节点从队列中移除。
                vec.push_back(node->val);  // 将节点的值添加到vec的末尾。
                if (node->left) {// 如果节点有左子节点,则将左子节点入队。
                    que.push(node->left);
                }
                if (node->right) { // 如果节点有右子节点,则将右子节点入队。
                    que.push(node->right);
                }
            }
            result.push_back(vec); // 将当前层的节点值一维数组vec添加到二维数组result中。
        }
        return result; // 返回包含层序遍历结果。
    }
};

//测试
// 辅助函数,用于创建一个新的TreeNode
TreeNode* createNode(int value) {
    return new TreeNode(value);
}

// 辅助函数,用于构建二叉树
TreeNode* buildTree(vector<int>& values) {
    if (values.empty()) return NULL;
    TreeNode* root = createNode(values[0]);
    queue<TreeNode*> queueNode;
    queueNode.push(root);
    int i = 1;
    while (!queueNode.empty()) {
        TreeNode* node = queueNode.front();
        queueNode.pop();
        if (i < values.size()) {
            node->left = createNode(values[i++]);
            queueNode.push(node->left);
        }
        if (i < values.size()) {
            node->right = createNode(values[i++]);
            queueNode.push(node->right);
        }
    }
    return root;
}

// 打印容器中的所有元素,用于验证测试结果
void printVector(const vector<vector<int>>& vec) {
    for (auto& ans : vec) {
        for (auto& i : ans) {
            cout << i << " ";
        }
    }
    cout << endl;
}

// 主函数
int main() {

    vector<int> treeValues = { 1, 2, 3, 4, 5, 6, 7 };// 定义二叉树的层序遍历结果,用于构建二叉树
    TreeNode* root = buildTree(treeValues); // 构建二叉树
    Solution1 s1;// 创建Solution类的实例
    Solution2 s2;
    vector<vector<int>> result1 = s1.levelOrder(root);// 传入二叉树的根节点
    vector<vector<int>> result2 = s2.levelOrder(root);
    cout << "二叉树的层序遍历(递归法)结果是: ";
    printVector(result1);
    cout << endl;
    cout << "二叉树的层序遍历(迭代法)结果是: ";
    printVector(result2);
    cout << endl;
    return 0;
}

二、翻转二叉树

1.题目

Leetcode:第 226 题

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例 1:

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例 2:

输入:root = [2,1,3]
输出:[2,3,1]

示例 3:

输入:root = []
输出:[]
2.解题思路

使用递归法和迭代法遍历二叉树并翻转

3.实现代码
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
using namespace std;

// 定义一个结构体TreeNode,用于表示二叉树的节点。
struct TreeNode {
    int val; // 存储节点的值。
    TreeNode* left; // 指向该节点左子树的指针。
    TreeNode* right; // 指向该节点右子树的指针。
    // TreeNode的构造函数,用于创建一个TreeNode实例。
    // 参数x是节点的值,left和right默认为NULL,表示没有左右子节点。
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

//一、二叉树的翻转(递归法)
class Solution1 {
public:
    // 定义名为invertTree的公共成员函数,用于翻转二叉树。
    // 函数接受一个参数:指向二叉树根节点的指针root。
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) {
            return root; // 如果根节点为空,则直接返回,无需翻转
        }

        //使用二叉树的前序遍历翻转二叉树
        swap(root->left, root->right);// 调用std::swap函数,交换当前节点的左右子节点。
        invertTree(root->left);// 递归地翻转左子树。
        invertTree(root->right);// 递归地翻转右子树。
        return root;// 由于递归调用会处理所有子节点,所以最终返回的是翻转后的二叉树的根节点。
    }

    /*
    // 定义名为invertTree的公共成员函数,用于翻转二叉树。
    // 函数接受一个参数:指向二叉树根节点的指针root。
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) {
            return root; // 如果根节点为空,则直接返回,无需翻转
        }

        //使用二叉树的中序遍历翻转二叉树
        //注意:使用中序遍历翻转时,先将root的左子树翻转完毕,再将root的左子树和右子树交换后,
        //此时的root的左子树是原来的右子树,因此需要对左子树再次翻转。
        invertTree(root->left);// 递归地翻转左子树。
        swap(root->left, root->right);// 调用std::swap函数,交换当前节点的左右子节点。
        invertTree(root->left);// 再次递归地翻转左子树。
        return root;// 由于递归调用会处理所有子节点,所以最终返回的是翻转后的二叉树的根节点。
    }
    */

    /*
    // 定义名为invertTree的公共成员函数,用于翻转二叉树。
    // 函数接受一个参数:指向二叉树根节点的指针root。
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) {
            return root; // 如果根节点为空,则直接返回,无需翻转
        }

        //使用二叉树的后序遍历翻转二叉树
        invertTree(root->left);// 递归地翻转左子树。
        invertTree(root->right);// 递归地翻转右子树。
        swap(root->left, root->right);// 调用std::swap函数,交换当前节点的左右子节点。
        return root;// 由于递归调用会处理所有子节点,所以最终返回的是翻转后的二叉树的根节点。
    }
    */
};

//二、二叉树的翻转(递归法)
class Solution2 {
public:
    // 定义名为invertTree的成员函数,接受一个指向TreeNode的指针作为参数。
    // 函数的目的是完成二叉树的翻转
	TreeNode* invertTree(TreeNode* root) {
        stack<TreeNode*> st;// 创建一个空的栈st,用于辅助进行前序遍历。
        if (root != NULL) {// 检查传入的二叉树根节点是否为空。
            st.push(root);// 如果根节点不为空,则将其压入栈中。
        }

        while (!st.empty()) { // 使用while循环进行遍历,直到栈为空。
            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); // 压入一个空指针作为前序遍历的分隔符。


                /*
                //使用二叉树的中序遍历翻转二叉树(迭代法)
                st.pop(); // 如果当前节点不为空,则将其从栈中弹出。
                if (node->right) {// 如果当前节点的右子节点不为空,则将其压入栈中。
                    st.push(node->right);// 如果当前节点的左子节点不为空,则将其压入栈中。
                }
                st.push(node);// 将当前节点再次压入栈中,这样做是为了在后续的遍历中能够访问到根节点。
                st.push(NULL); // 压入一个空指针作为前序遍历的分隔符。
                if (node->left) {
                    st.push(node->left);
                }
                */

                /*
              //使用二叉树的后序遍历翻转二叉树(迭代法)
              st.pop(); // 如果当前节点不为空,则将其从栈中弹出。
              st.push(node);// 将当前节点再次压入栈中,这样做是为了在后续的遍历中能够访问到根节点。
              st.push(NULL); // 压入一个空指针作为前序遍历的分隔符。
              if (node->right) {// 如果当前节点的右子节点不为空,则将其压入栈中。
                  st.push(node->right);// 如果当前节点的左子节点不为空,则将其压入栈中。
              }
              if (node->left) {
                  st.push(node->left);
              }
              */
            }
            else {// 如果node为空,说明栈顶元素是NULL,这表示已经处理完一个节点的左右子树
                st.pop();// 弹出栈顶元素(此时是NULL)
                node = st.top();// 获取当前节点。
                st.pop();// 弹出当前节点,并将其值添加到结果中。
                swap(node->left, node->right);
            }
        }
        return root;// 返回包含前序遍历结果。
    }
};

三、对称二叉树

1.题目

Leetcode:第 101 题

给你一个二叉树的根节点 root , 检查它是否轴对称。

示例 1:

输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

输入:root = [1,2,2,null,3,null,3]
输出:false
2.解题思路

使用递归法和迭代法遍历二叉树,判断节点是否对称

3.实现代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

// 定义一个结构体TreeNode,用于表示二叉树的节点。
struct TreeNode {
    int val; // 存储节点的值。
    TreeNode* left; // 指向该节点左子树的指针。
    TreeNode* right; // 指向该节点右子树的指针。
    // TreeNode的构造函数,用于创建一个TreeNode实例。
    // 参数x是节点的值,left和right默认为NULL,表示没有左右子节点。
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
// 一、判断二叉的对称性(递归法)
class Solution1 {
public:
    // 定义名为compare的辅助函数,用于比较两棵树是否镜像对称。
    // 函数接受两个参数:指向二叉树节点的指针left和right。
    bool compare(TreeNode* left, TreeNode* right) {

        // 如果left为空且right不为空,或者left不为空且right为空,返回false。
        if (left == NULL && right != NULL)  return false;
        else if (left != NULL && right == NULL)  return false;

        // 如果两个节点都为空,说明已经到达了树的同一层的末尾,返回true。
        else if (left == NULL && right == NULL) return true;

        // 如果两个节点的值不相等,返回false。
        else if (left->val != right->val) return false;

        // 递归比较左子树和右子树的镜像位置节点。
        // outside是left的左子节点与right的右子节点的比较结果。
        bool outside = compare(left->left, right->right);

        // 递归比较左子树和右子树的镜像位置节点。
        // inside是left的右子节点与right的左子节点的比较结果。
        bool inside = compare(left->right, right->left);

        // 判断两个树是否在当前层镜像对称。
        // 如果outside和inside都为true,则说明当前层的两个对应节点及其子树都是镜像对称的。
        bool isSame = outside && inside;
        // 返回判断结果。
        return isSame;
    }

    // 定义名为isSymmetric的成员函数,用于判断一棵二叉树是否对称。
    // 函数接受指向二叉树根节点的指针root。
    bool isSymmetric(TreeNode* root) {
        // 如果根节点为空,说明是一棵空树,空树是对称的,返回true。
        if (root == NULL) return true;

        // 调用compare函数判断根节点的左右子树是否镜像对称。
        // 这里传入的参数是root->left和root->right,分别对应根节点的左子树和右子树。
        return compare(root->left, root->right);
    }
};

// 二、判断二叉的对称性(迭代法)(也可直接将队列替换为栈)
class Solution2 {
public:
    // 定义名为isSymmetric的成员函数,函数接受指向二叉树根节点的指针root。
    // 函数用于判断一棵二叉树是否对称。
    bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;// 如果根节点为空,说明是一棵空树,空树是对称的,返回true。
        queue<TreeNode*> que;// 创建一个队列que,用于存储待比较的节点。

        // 将根节点的左子节点和右子节点入队。
        que.push(root->left);
        que.push(root->right);


        while (!que.empty()) {  // 使用while循环进行遍历,直到队列为空。
           
            TreeNode* leftNode = que.front(); // 取出队列前端的节点,即左子树的根节点。
            que.pop();
            
            TreeNode* rightNode = que.front();// 取出队列前端的节点,即右子树的根节点。
            que.pop();
            
            if (leftNode == NULL && rightNode == NULL) {// 如果两个节点都为空,说明已经匹配了一对空节点,继续下一次循环。
                continue;
            }

            // 如果两个节点中有一个为空,或者两个节点的值不相等,返回false。
            // 这表示两个子树在对应位置的节点不匹配,因此整棵树不是对称的。
            if (leftNode == NULL || rightNode == NULL || (leftNode->val != rightNode->val)) {
                return false;
            }

            // 将要比较的节点入队,左子树的左子节点与右子树的右子节点比较,
            // 左子树的右子节点与右子树的左子节点比较。
            que.push(leftNode->left);
            que.push(rightNode->right);
            // 继续比较下一层节点,左子树的右子节点与右子树的左子节点比较,
            // 右子树的左子节点与左子树的左子节点比较。
            que.push(leftNode->right);
            que.push(rightNode->left);

        }
        // 如果所有节点都匹配成功,返回true,说明整棵树是对称的。
        return true;
    }
};


//测试
// 辅助函数,用于创建一个新的TreeNode
TreeNode* createNode(int value) {
    return new TreeNode(value);
}

// 辅助函数,用于构建二叉树
TreeNode* buildTree(vector<int>& values) {
    if (values.empty()) return NULL;
    TreeNode* root = createNode(values[0]);
    queue<TreeNode*> queueNode;
    queueNode.push(root);
    int i = 1;
    while (!queueNode.empty()) {
        TreeNode* node = queueNode.front();
        queueNode.pop();
        if (i < values.size()) {
            node->left = createNode(values[i++]);
            queueNode.push(node->left);
        }
        if (i < values.size()) {
            node->right = createNode(values[i++]);
            queueNode.push(node->right);
        }
    }
    return root;
}

// 打印容器中的所有元素,用于验证测试结果
void printVector(const vector<vector<int>>& vec) {
    for (auto& ans : vec) {
        for (auto& i : ans) {
            cout << i << " ";
        }
    }
    cout << endl;
}

// 主函数
int main() {

    vector<int> treeValues = { 1, 2, 2, 3, 4, 4, 3 };// 定义二叉树的层序遍历结果,用于构建二叉树
    TreeNode* root = buildTree(treeValues); // 构建二叉树
    Solution1 s1;// 创建Solution类的实例
    Solution2 s2;
    int result1 = s1.isSymmetric(root);// 传入二叉树的根节点
    int result2 = s2.isSymmetric(root);
    cout << "判断二叉的对称性(递归法)的结果是: " << result1 << endl;
    cout << endl;
    cout << "判断二叉的对称性(迭代法)的结果是: " << result2 << endl;
    cout << endl;
    return 0;
}

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值