LeetCode分类刷题(八):二叉树(Tree)(1)

树是一种比较重要的数据结构,尤其是二叉树。二叉树是一种特殊的树,在二叉树中每个节点最多有两个子节点,一般称为左子节点和右子节点(或左孩子和右孩子),并且二叉树的子树有左右之分,其次序不能任意颠倒。二叉树是递归定义的,因此,与二叉树有关的题目基本都可以用递归思想解决当然有些题目非递归解法也应该掌握,如非递归遍历节点等等。本文努力对二叉树相关题目做一个较全的整理总结,希望对找工作的同学有所帮助。
二叉树节点定义如下:

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

LeetCode中关于二叉树的基础题目有以下五种类型题:

(1)二叉树之深度遍历相关题目:

(2)二叉树之层遍历相关题目:

(3)二叉树之深度相关题目:

(4)二叉树之侧视图相关题目:

(5)二叉树之递归应用相关题目:


(1)二叉树之深度遍历相关题目:

144. Binary Tree Preorder Traversal

  • Given a binary tree, return the preorder traversal of its nodes' values.
  • 题目要求:不使用递归操作,先序遍历二叉树。
  • 题目分析:用到stack来辅助运算。由于先序遍历的顺序是"根-左-右", 算法为:1. 把根节点push到栈中;2. 循环检测栈是否为空,若不空,则取出栈顶元素,保存其值,然后看其右子节点是否存在,若存在则push到栈中。再看其左子节点,若存在,则push到栈中。
  • 题目解答:
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> stk;
        TreeNode *cur = root;
        while(stk.size() || cur){
            if(cur){
                res.push_back(cur->val);
                stk.push(cur);
                cur = cur->left;
            }else{
                cur = stk.top();
                stk.pop();
                cur = cur->right;
            }
        }
        return res;
    }
};

94. Binary Tree Inorder Traversal

  • Given a binary tree, return the inorder traversal of its nodes' values.
  • 题目要求:不使用递归操作,中序遍历二叉树。
  • 题目分析:二叉树的中序遍历顺序为左-根-右,可以有递归和非递归来解,其中非递归解法又分为两种,一种是使用栈来接,另一种不需要使用栈。我们先来看递归方法,十分直接,对左子结点调用递归函数,根节点访问值,右子节点再调用递归函数。
  • 题目解答:
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> stk;
        TreeNode *cur = root;
        while(stk.size() || cur){
            if(cur){
                stk.push(cur);
                cur = cur->left;
            }else{
                cur = stk.top();
                stk.pop();
                res.push_back(cur->val);
                cur = cur->right;
            }
        }
        return res;
    }
};

145. Binary Tree Postorder Traversal

  • Given a binary tree, return the postorder traversal of its nodes' values.
  • 题目要求:不使用递归操作,后序遍历二叉树。
  • 题目分析:因为后序非递归遍历二叉树的顺序是先访问左子树,再访问右子树,最后访问根节点。当用堆栈来存储节点,必须分清返回根节点时,是从左子树返回的,还从右子树返回的。所以,使用辅助指针pre,其指向最近访问过的节点。也可以在节点中增加一个标志域,记录是否已被访问。
  • 题目解答:
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> stk;
        TreeNode *cur = root, *pre = nullptr;
        while(stk.size() || cur){
            if(cur){
                stk.push(cur);
                cur = cur->left;
            }else{
                cur = stk.top();
                if(cur->right == nullptr || cur->right == pre){
                    stk.pop();
                    res.push_back(cur->val);
                    pre = cur;
                    cur = nullptr;
                }else{
                    cur = cur->right;
                }
            }
        }
        return res;
    }
};

(2)二叉树之层遍历相关题目:

102. Binary Tree Level Order Traversal

  • Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).
  • 题目要求:从左到右进行层遍历。
  • 题目分析:层序遍历二叉树是典型的广度优先搜索BFS的应用,但是这里稍微复杂一点的是,我们要把各个层的数分开,存到一个二维向量里面,大体思路还是基本相同的,建立一个queue,然后先把根节点放进去,这时候找根节点的左右两个子节点,这时候去掉根节点,此时queue里的元素就是下一层的所有节点,用一个for循环遍历它们,然后存到一个一维向量里,遍历完之后再把这个一维向量存到二维向量里,以此类推,可以完成层序遍历。
  • 题目解答:
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        vector<int> level;
        if(root == nullptr) return res;
        queue<TreeNode*> que;
        que.push(root);
        que.push(nullptr);
        TreeNode *cur = nullptr;
        while(que.size()){
            cur = que.front();
            que.pop();
            if(cur){
                level.push_back(cur->val);
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }else{
                res.push_back(level);
                level.resize(0);
                if(que.size() > 0) que.push(nullptr);
            }
        }
        return res;
    }
};

107. Binary Tree Level Order Traversal II

  • Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).
  • 题目要求:从左到右,从底向上,进行层遍历。
  • 题目分析:与上面题目相似,从底部层序遍历其实还是从顶部开始遍历,只不过最后存储的方式有所改变。
  • 题目解答:
class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> res;
        vector<int> level;
        if(root == nullptr) return res;
        queue<TreeNode*> que;
        que.push(root);
        que.push(nullptr);
        TreeNode *cur = nullptr;
        while(que.size()){
            cur = que.front();
            que.pop();
            if(cur){
                level.push_back(cur->val);
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }else{
                res.insert(res.begin(), level);
                level.resize(0);
                if(que.size() > 0) que.push(nullptr);
            }
        }
        return res;
    }
};

103. Binary Tree Zigzag Level Order Traversal

  • Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).
  • 题目要求:按照Z字形,进行层遍历。
  • 题目分析:与上面题目相似,只不过最后存储的方式有所改变。
  • 题目解答:
class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> res;
        vector<int> level;
        if(root == nullptr) return res;
        queue<TreeNode*> que;
        que.push(root);
        que.push(nullptr);
        TreeNode *cur = nullptr;
        int flag = 1;
        while(que.size()){
            cur = que.front();
            que.pop();
            if(cur){
                if(flag % 2)level.push_back(cur->val);
                else level.insert(level.begin(), cur->val);
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }else{
                res.push_back(level);
                level.resize(0);
                if(que.size() > 0) que.push(nullptr);
                flag++;
            }
        }
        return res;
    }
};

(3)二叉树之深度相关题目:

104. Maximum Depth of Binary Tree

  • Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
  • 题目要求:给定一个二叉树,找出它的最大深度。 最大深度是指的从根节点一直到最远的叶节点中所有的节点数目。
  • 题目分析:求二叉树的最大深度问题用到深度优先搜索DFS,递归的完美应用。
  • 题目解答:
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        if(root->left == nullptr && root->right == nullptr) return 1;
        int maxleft = maxDepth(root->left);
        int maxright = maxDepth(root->right);
        return max(maxleft, maxright) + 1;
    }
};

110. Balanced Binary Tree

  • Given a binary tree, determine if it is height-balanced.
  • 题目要求:求二叉树是否平衡,根据题目中的定义,高度平衡二叉树是每一个结点的两个子树的深度差不能超过1。
  • 题目分析:我们肯定需要一个求各个点深度的函数,然后对每个节点的两个子树来比较深度差,时间复杂度为O(NlgN)。
  • 题目解答:
class Solution {
public:
    bool isBalanced(TreeNode* root) {
        if(root == nullptr) return true;
        int l_depth = maxDepth(root->left);
        int r_depth = maxDepth(root->right);
        return abs(l_depth - r_depth) <= 1&& isBalanced(root->left) && isBalanced(root->right);
    }
    int maxDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        if(root->left == nullptr && root->right == nullptr) return 1;
        int maxleft = maxDepth(root->left);
        int maxright = maxDepth(root->right);
        return max(maxleft, maxright) + 1;
    }
};

543. Diameter of Binary Tree

  • Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a binary tree is the length of the longestpath between any two nodes in a tree. This path may or may not pass through the root.
  • 题目要求:求二叉树的直径,并告诉了我们直径就是两点之间的最远距离。
  • 题目分析:我们只要对每一个结点求出其左右子树深度之和,这个值作为一个候选值,然后再对左右子结点分别调用求直径对递归函数,这三个值相互比较,取最大的值更新结果res,因为直径不一定会经过根结点,所以才要对左右子结点再分别算一次。
  • 题目解答:
class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root) {
        if(root == nullptr) return 0;
        int l_depth = maxDepth(root->left);
        int r_depth = maxDepth(root->right);
        return max(l_depth + r_depth, max(diameterOfBinaryTree(root->left), diameterOfBinaryTree(root->right)));
    }
    int maxDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        if(root->left == nullptr && root->right == nullptr) return 1;
        int maxleft = maxDepth(root->left);
        int maxright = maxDepth(root->right);
        return max(maxleft, maxright) + 1;
    }
};

111. Minimum Depth of Binary Tree

  • Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
  • 题目要求:给定一个二叉树,找出它的最短深度。 最短深度是指从节点到最近的叶节点的最短距离。
  • 题目分析:二叉树的经典问题之最小深度问题就是就最短路径的节点个数,还是用深度优先搜索DFS来完成,万能的递归啊。
  • 题目解答:
class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        if(root->left == nullptr && root->right == nullptr) return 1;
        int minleft = minDepth(root->left);
        int minright = minDepth(root->right);
        if(minleft == 0 || minright == 0) return minleft + minright + 1;
        else return 1 + min(minDepth(root->left), minDepth(root->right));
    }
};

(4)二叉树之侧视图相关题目:

199. Binary Tree Right Side View

  • Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
  • 题目要求:这道题要求我们打印出二叉树每一行最右边的一个数字。
  • 题目分析:实际上是求二叉树层序遍历的一种变形,我们只需要保存每一层最右边的数字即可,这道题只要在之前层遍历那道题上稍加修改即可得到结果,还是需要用到数据结构队列queue,遍历每层的节点时,把下一层的节点都存入到queue中,每当开始新一层节点的遍历之前,先把新一层最后一个节点值存到结果中。
  • 题目解答:
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> res;
        if(root == nullptr) return res;
        queue<TreeNode*> que;
        que.push(root);
        while(que.size()){
            res.push_back(que.back()->val);
            int len = que.size();
            for(int i = 0; i < len; i++){
                TreeNode* node = que.front();
                que.pop();
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return res;
    }
};

513. Find Bottom Left Tree Value

  • Given a binary tree, find the leftmost value in the last row of the tree.
  • 题目要求:这道题让我们求二叉树的最左下树结点的值,也就是最后一行左数第一个值。
  • 题目分析:这道题用层序遍历更直接一些,因为层序遍历时遍历完当前行所有结点之后才去下一行,那么我们再遍历每行第一个结点时更新结果res即可。
  • 题目解答:
class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        vector<int> res;
        if(root == nullptr) return 0;
        queue<TreeNode*> que;
        que.push(root);
        while(que.size()){
            res.push_back(que.front()->val);
            int len = que.size();
            for(int i = 0; i < len; i++){
                TreeNode* node = que.front();
                que.pop();
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return res.back();
    }
};

515. Find Largest Value in Each Tree Row

  • You need to find the largest value in each row of a binary tree.
  • 题目要求:这道题让我们找二叉树每行的最大的结点值。
  • 题目分析:最直接的方法就是用层序遍历,然后在每一层中找到最大值,加入结果res中即可。
  • 题目解答:
class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        vector<int> res;
        if(root == nullptr) return res;
        queue<TreeNode*> que;
        que.push(root);
        while(que.size()){
            int len = que.size();
            int temp = INT_MIN;
            for(int i = 0; i < len; i++){
                TreeNode* node = que.front();
                que.pop();
                temp = max(temp, node->val);
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
            res.push_back(temp);
        }
        return res;
    }
};

(5)二叉树之递归应用相关题目:

100. Same Tree

  • Given two binary trees, write a function to check if they are the same or not.
  • 题目要求:判断两棵树是否相同。
  • 题目分析:利用深度优先搜索DFS来递归。
  • 题目解答:
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p == nullptr && q == nullptr) return true;
        if(p == nullptr || q == nullptr) return false;
        if(p->val != q->val) return false;
        return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    }
};

101. Symmetric Tree

  • Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
  • 题目要求:判断一棵树是否对称。
  • 题目分析:利用深度优先搜索DFS来递归。
  • 题目解答:
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
       return root == nullptr || isSymmetricTree(root->left, root->right);
    }
    bool isSymmetricTree(TreeNode* p, TreeNode* q) {
        if(p == nullptr && q == nullptr) return true;
        if(p == nullptr || q == nullptr) return false;
        if(p->val != q->val) return false;
        return isSymmetricTree(p->left, q->right) && isSymmetricTree(p->right, q->left);
    }
};

572. Subtree of Another Tree

  • Given two non-empty binary trees s and t, check whether tree t has exactly the same structure and node values with a subtree of s. A subtree of s is a tree consists of a node in s and all of this node's descendants. The tree s could also be considered as a subtree of itself.
  • 题目要求:这道题让我们求一个数是否是另一个树的子树。
  • 题目分析:子树必须是从叶结点开始的,中间某个部分的不能算是子树,那么我们转换一下思路,是不是从s的某个结点开始,跟t的所有结构都一样,那么问题就转换成了判断两棵树是否相同,也就是两棵树是否相同的问题了,用递归来写十分的简洁,我们先从s的根结点开始,跟t比较,如果两棵树完全相同,那么返回true,否则就分别对s的左子结点和右子结点调用递归再次来判断是否相同,只要有一个返回true了,就表示可以找得到。
  • 题目解答:
class Solution {
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(s == nullptr) return false;
        if(isSameTree(s, t)) return true;
        return isSubtree(s->left, t) || isSubtree(s->right, t);
    }
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p == nullptr && q == nullptr) return true;
        if(p == nullptr || q == nullptr) return false;
        if(p->val != q->val) return false;
        return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    }
};

226. Invert Binary Tree

  • Invert a binary tree.
  • 题目要求:这道题让我们翻转二叉树。
  • 题目分析:利用三种方法求解问题。
  • 题目解答:
class Solution {
public:
    TreeNode* invertTree1(TreeNode* root){
        if(root){
            invertTree(root->left); 
            invertTree(root->right);
            swap(root->left, root->right);
        }
        return root;
    }
    TreeNode* invertTree2(TreeNode* root){
        stack<TreeNode*> stk;
        stk.push(root);
        TreeNode *cur = root;
        while(stk.size()){
            cur = stk.top();
            stk.pop();
            if(cur){
                stk.push(cur->left);
                stk.push(cur->right);
                swap(cur->left, cur->right);
            }
        }
        return root;
    }
    TreeNode* invertTree(TreeNode* root){
        queue<TreeNode*> que;
        que.push(root);
        TreeNode *cur;
        while(que.size()){
            cur = que.front();
            que.pop();
            if(cur){
                que.push(cur->left);
                que.push(cur->right);
                swap(cur->left, cur->right);
            }
        }
        return root;
    }
};

如果各位看官们,大神们发现了任何错误,或是代码无法通过OJ,或是有更好的解法,或是有任何疑问,意见和建议的话,请一定要在帖子下面评论区留言告知博主啊,多谢多谢,祝大家刷得愉快,刷得精彩,刷出美好未来~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值