代码随想录训练营第15天|二叉树的层序遍历、LeetCode 226.翻转二叉树、LeetCode 101.对称二叉树II

参考

代码随想录

二叉树的层序遍历

二叉树的层序遍历要借助队列来实现,队列先进先出,符合一层一层遍历的逻辑,而是用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。层序遍历的一般步骤如下:
(1)初始化。定义一个队列,将根结点放入队列中。
(2)从队首读一个元素,处理该节点,然后将该节点的左右节点分别加入队列中(如果该节点有子节点)。重复这个过程直到队列为空。
按照上述步骤就可以把二叉树的遍历结果放入整个数组中,但是如果需要将每一层的结果分开来,就需要稍作修改。以下图为例,说明二叉树的层序遍历过程。
在这里插入图片描述

  • 初始化,将根结点放入队列中
    在这里插入图片描述
  • 读取队首元素进行处理,然后将其左右子节点加入队列
    在这里插入图片描述
    在这里插入图片描述

题目一:102. 二叉树的层序遍历

/**
 * 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>> levelOrder(TreeNode* root) {
        if(root == nullptr) return {};
        vector<vector<int>> result;
        vector<int> tmp;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            tmp.clear();
            for(int i=0;i<size;i++)
            {
                TreeNode* node = que.front();
                que.pop();
                tmp.push_back(node->val);
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)  que.push(node->right);
            }
            result.push_back(tmp);
        }
        return result;
    }
};

上面的代码中的while循环中的for循环的作用就是将每一层的结果放入到一个数组中。

题目二:107. 二叉树的层序遍历II

/**
 * 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>> levelOrderBottom(TreeNode* root) {
        if(root == nullptr) return {};
        vector<vector<int>> result;
        vector<int> tmp;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            tmp.clear();
            for(int i=0;i<size;i++)
            {
                TreeNode* node = que.front();
                que.pop();
                tmp.push_back(node->val);
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)  que.push(node->right);
            }
            result.push_back(tmp);
        }
        reverse(result.begin(),result.end());
        return result;
    }
};

这个题在上一个题上将结果反转就可以了,没有难点。

题目三:199. 二叉树的右视图

/**
 * 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<int> rightSideView(TreeNode* root) {
        if(root == nullptr) return {};
        vector<int> result;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            for(int i=0;i<size;i++)
            {
                TreeNode* node = que.front();
                que.pop();
                if(i == size-1) //只保存最后一个节点
                    result.push_back(node->val);
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)  que.push(node->right);
            }
            
        }
        return result;
    }
};

在保存节点的时候只保存最后一个节点就可以了。

题目四:637. 二叉树的层平均值

/**
 * 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<double> averageOfLevels(TreeNode* root) {
        if(root == nullptr) return{};
        vector<double> result;
        
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            double tmp = 0;
            for(int i=0;i<size;i++)
            {
                TreeNode* node = que.front();
                que.pop();
                tmp += node->val;
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)  que.push(node->right);
            }
            result.push_back(tmp/size);
        }
        return result;
    }
};

题目五:429. N叉树的层序遍历

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        if(root == nullptr) return {};
        vector<vector<int>> result;
        vector<int> tmp;
        queue<Node*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            tmp.clear();
            for(int i=0;i<size;i++)
            {
                Node* node = que.front();
                que.pop();
                tmp.push_back(node->val);
                for(int j=0;j<(node->children).size();j++)  //添加子节点
                    que.push(node->children[j]);
            }
            result.push_back(tmp);
        }
        return result;
    }
};

换汤不换药,一样遍历就行了。

题目六:515.在在每个树行中找最大值

/**
 * 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<int> largestValues(TreeNode* root) {
        if(root == nullptr) return {};
        vector<int> result;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            int max = INT_MIN;
            for(int i=0;i<size;i++)
            {
                TreeNode* node = que.front();
                que.pop();
                if(node->val > max) max = node->val;
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)  que.push(node->right);
            }
            result.push_back(max);
        }
        return result;
    }
};

题目七:116. 填充每个节点的下一个右侧节点指针

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;
    Node* next;

    Node() : val(0), left(NULL), right(NULL), next(NULL) {}

    Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

    Node(int _val, Node* _left, Node* _right, Node* _next)
        : val(_val), left(_left), right(_right), next(_next) {}
};
*/

class Solution {
public:
    Node* connect(Node* root) {
        if(root == nullptr) return nullptr;
        queue<Node*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            if(size > 1)
            {
                for(int i=0;i<size-1;i++)
                {
                    Node* node = que.front();
                    que.pop();
                    node->next = que.front();
                    if(node->left != nullptr)   que.push(node->left);
                    if(node->right != nullptr)  que.push(node->right);
                }
                que.front()->next = nullptr;
                if(que.front()->left != nullptr) que.push(que.front()->left);
                if(que.front()->right != nullptr) que.push(que.front()->right);
                que.pop();
            }
            else
            {
                Node* node = que.front();
                node->next = nullptr;
                que.pop();
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)  que.push(node->right);
            }
        }
        return root;
    }
};

题目八:填充每个节点的下一个右侧节点指针 II

class Solution {
public:
    Node* connect(Node* root) {
        if(root == nullptr) return nullptr;
        queue<Node*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            if(size > 1)
            {
                for(int i=0;i<size-1;i++)
                {
                    Node* node = que.front();
                    que.pop();
                    node->next = que.front();
                    if(node->left != nullptr)   que.push(node->left);
                    if(node->right != nullptr)  que.push(node->right);
                }
                que.front()->next = nullptr;
                if(que.front()->left != nullptr) que.push(que.front()->left);
                if(que.front()->right != nullptr) que.push(que.front()->right);
                que.pop();
            }
            else
            {
                Node* node = que.front();
                node->next = nullptr;
                que.pop();
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)  que.push(node->right);
            }
        }
        return root;
    }
};

上一个题的二叉树是完美二叉树,这个题是一般的二叉树,但在代码实现上没有任何区别,直接复制上一个题的代码就行。

题目九:104. 二叉树的最大深度

/**
 1. Definition for a binary tree node.
 2. struct TreeNode {
 3.     int val;
 4.     TreeNode *left;
 5.     TreeNode *right;
 6.     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 7.     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 8.     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 9. };
 */
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        queue<TreeNode*> que;
        int cnt = 0;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            for(int i=0;i<size;i++)
            {
                TreeNode* node = que.front();
                que.pop();
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)   que.push(node->right);
            }
            cnt++;
        }
        return cnt;
    }
};

题目十:111. 二叉树的最小深度

/**
 10. Definition for a binary tree node.
 11. struct TreeNode {
 12.     int val;
 13.     TreeNode *left;
 14.     TreeNode *right;
 15.     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 16.     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 17.     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 18. };
 */
class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        queue<TreeNode*> que;
        int depth = 0;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            depth++;
            for(int i=0;i<size;i++)
            {
                TreeNode* node = que.front();
                que.pop();
                if(node != root && node->left == nullptr 
                    && node->right == nullptr)
                    return depth;
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)   que.push(node->right);
            }
        }
        return depth;
    }
};

从第二层可开始,如果某一个节点既没有左子节点也没有右节点,则该节点就是满足条件的叶子节点。

LeetCode 226.翻转二叉树

深度优先(递归法)

注意在递归法历里不能使用中序遍历!!!
递归三部曲
第一步,确定递归函数的参数和返回值。这个题的要求是反转每个节点的子节点,因此不需要返回值,参数就是某个节点。

void recursion(TreeNode* node);

第二步,确定递归终止条件。当传入的节点为空时,终止递归。

if(node == nullptr)	return;

第三步,确定单层递归逻辑。交换传入节点的两个子节点:

swap(node->left,node->right);
recursion(node->left);
recursion(node->right);

完整代码实现如下:

/**
 19. Definition for a binary tree node.
 20. struct TreeNode {
 21.     int val;
 22.     TreeNode *left;
 23.     TreeNode *right;
 24.     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 25.     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 26.     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 27. };
 */
class Solution {
public:
    void recursion(TreeNode* node)
    {
        if(node == nullptr) return;
        swap(node->left,node->right);
        recursion(node->left);
        recursion(node->right);
    }

    TreeNode* invertTree(TreeNode* root) {
        recursion(root);
        return root;
    }
};

上面的代码使用的是前序遍历,后序遍历的代码如下:

/**
 28. Definition for a binary tree node.
 29. struct TreeNode {
 30.     int val;
 31.     TreeNode *left;
 32.     TreeNode *right;
 33.     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 34.     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 35.     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 36. };
 */
class Solution {
public:
    void recursion(TreeNode* node)
    {
        if(node == nullptr) return;
        recursion(node->left);
        recursion(node->right);
        swap(node->left,node->right);
    }

    TreeNode* invertTree(TreeNode* root) {
        recursion(root);
        return root;
    }
};

深度优先(统一迭代法)

/**
 37. Definition for a binary tree node.
 38. struct TreeNode {
 39.     int val;
 40.     TreeNode *left;
 41.     TreeNode *right;
 42.     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 43.     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 44.     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 45. };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == nullptr) return nullptr;   
        stack<TreeNode*> stk;
        stk.push(root);
        while(!stk.empty())
        {
            TreeNode* node = stk.top();
            stk.pop();
            if(node != nullptr)
            {
                stk.push(node);         //中
                stk.push(nullptr);
                if(node->left != nullptr)stk.push(node->left);   //左
                if(node->right != nullptr)stk.push(node->right);   //右
            }
            else
            {
                node = stk.top();
                stk.pop();
                swap(node->left,node->right);
            }
        }
        return root;
    }
};

上面的代码是前序遍历,中序遍历和后序遍历的做相应修改就可以了。注意,迭代遍历中是可以使用中序遍历的。

广度优先(层序遍历)

/**
 46. Definition for a binary tree node.
 47. struct TreeNode {
 48.     int val;
 49.     TreeNode *left;
 50.     TreeNode *right;
 51.     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 52.     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 53.     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 54. };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == nullptr) return nullptr;   
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty())
        {
            int size = que.size();
            for(int i=0;i<size;i++)
            {
                TreeNode* node = que.front();
                que.pop();
                swap(node->left,node->right);
                if(node->left != nullptr)   que.push(node->left);
                if(node->right != nullptr)  que.push(node->right);
            }
        }
        return root;
    }
};

LeetCode 101. 对称二叉树

递归法

  1. 确定递归函数的参数和返回值
    因为比较两个子节点,所以参数必须有两个子节点,返回值是bool类型,即是否相等(对称)
bool compare(TreeNode* node1,TreeNode* node2);
  1. 确定终止条件
    终止的情况有以下几种:
  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return false
  • 左右都为空,对称,返回true
  • 左右都不为空,比较节点数值,不相同就return false
if(node1 == nullptr && node2 != nullptr)	return false;
else if(node1 != nullptr && node2 == nullptr)	return false;
else if(node1 == nullptr && node2 == nullptr)	return true;
else if(node1->val != node2->val)	return false;
  1. 确定单层递归逻辑
    当两个节点都不为空且数值相等的情况下才进入单层递归逻辑的处理。
  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。
bool outside = compare(node1->left,node2->right);
bool inside = compare(node1->right,node2->left);
bool isSame = outside && inside;

完整的代码如下:

/**
 * 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* node1,TreeNode* node2)
    {
        if(node1 == nullptr && node2 != nullptr)	return false;
        else if(node1 != nullptr && node2 == nullptr)	return false;
        else if(node1 == nullptr && node2 == nullptr)	return true;
        else if(node1->val != node2->val)	return false;

        bool outside = compare(node1->left,node2->right);
        bool inside = compare(node1->right,node2->left);
        bool isSame = outside && inside;
        return isSame;
    }

    bool isSymmetric(TreeNode* root) {
        if(root == nullptr) return true;
        return compare(root->left,root->right);
    }
};

迭代法(用栈迭代)

/**
 * 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) {
        if(root == nullptr) return true;
        stack<TreeNode*> stk;
        stk.push(root->left);
        stk.push(root->right);
        while(!stk.empty())
        {
            TreeNode* node1 = stk.top();
            stk.pop();
            TreeNode* node2 = stk.top();
            stk.pop();
            if(node1 == nullptr && node2 == nullptr)   continue;
            else if(node1 == nullptr && node2 != nullptr)   return false;
            else if(node1 != nullptr && node2 == nullptr)   return false;
            
            stk.push(node1->left);
            stk.push(node2->right);
            stk.push(node1->right);
            stk.push(node2->left);
            
            if(node1->val != node2->val)    return false;
        }
        return true;
    }
};

这里不是标准的前序遍历,但是用的是一样的思路。注意下面的语句里用的continue而不能直接返回:

if(node1 == nullptr && node2 == nullptr)   continue;

此外要注意压栈顺序,外侧两个节点要一起压栈,内侧的两个节点也如此,这样在弹出两个即节点时才是对应的两个节点。

迭代法(用队列迭代)

/**
 * 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) {
        if(root == nullptr) return true;
        queue<TreeNode*> que;
        que.push(root->left);
        que.push(root->right);
        while(!que.empty())
        {
            TreeNode* node1 = que.front();
            que.pop();
            TreeNode* node2 = que.front();
            que.pop();

            if(node1 == nullptr && node2 == nullptr)   continue;
            else if(node1 == nullptr && node2 != nullptr)   return false;
            else if(node1 != nullptr && node2 == nullptr)   return false;

            que.push(node1->left);
            que.push(node2->right);
            que.push(node1->right);
            que.push(node2->left);

            if(node1->val != node2->val)    return false;
        }
        return true;
    }
};

用队列迭代和用栈迭代基本一致。用栈迭代类似于二叉树的层序遍历,只是入队顺序由原来的从左到右变为从两侧到中间。

今日小结

今天的内容是二叉树的层序遍历、翻转和对称判断,层序遍历是二叉树遍历的最基本的一种,翻转和对称是二叉树的一个简单应用,从本质上看还是考虑如何遍历二叉树,但这种遍历不是常规的几种遍历,要根据具体的要求来确定遍历顺序,例如翻转这个题,我们只需要将每个节点的两个子节点进行反转就可以了,所以可以用递归遍历(不能使用中序遍历),也可以统一迭代遍历,还可以用层序遍历,方法较多,不限制遍历顺序,但是判断对称性这个题只能从每一层的两侧往里遍历或者从中间往两侧遍历,不能用常规的遍历方法,但也是用常规方法的简单变形,因此掌握二叉树的基本遍历方法很重要!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆昔z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值