LeetCode分类刷题:二叉树(Tree)——(二叉树之前序、中序、后序、层次遍历、深度相关、侧视图相关)

二叉树(Tree)

1、定义

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

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

2、二叉树之前序、中序、后序遍历

2.1、前序遍历

1、题目分析:用到stack来辅助运算。由于先序遍历的顺序是"根-左-右", 算法为:1. 把根节点push到栈中;2. 循环检测栈是否为空,若不空,则取出栈顶元素,保存其值,然后看其右子节点是否存在,若存在则push到栈中。再看其左子节点,若存在,则push到栈中。

class Solution {
public:
    vector<int>preorderTraversal(TreeNode *root)
		{
		     vector<int> path;
		     if(root == NULL)
		     	return path;
		    stack<TreeNode *> s;
		    TreeNode *p = root;
		    while(p != NULL || !s.empty())
		    {
		        while(p != NULL)
		        {
		            path.push_back(p->val);
		            s.push(p);
		            p = p->left;
		        }
		        if(!s.empty())
		        {
		            p = s.top();
		            s.pop();
		            p = p->right;
		        }
		    }
		    return path;
	}
};


vector<int>preorderTraversal(TreeNode *root)
		{
		    vector<int> path;
		     if(root == NULL)
		     	return path;
		    stack<TreeNode *> s;
		    s.push(root);
		    TreeNode *p = NULL;
		    while( !s.empty())
		    {
		         p = s.top();
		         s.pop():
		         path.push_back(p->val);

		        if(p->right != NULL)
		        {
		             s.push(p->right);
		        }
		        if(p->left != NULL)
		        {
		             s.push(p->left);
		        }
		    }
		    return path;
	}

2.2、中序遍历

void inorderTraversal(TreeNode *root, vector<int> &path)
{
    stack<TreeNode *> s;
    TreeNode *p = root;
    while(p != NULL || !s.empty())
    {
        while(p != NULL)
        {
            s.push(p); 
            p = p->left;
        }
        if(!s.empty())
        {
            p = s.top();
            path.push_back(p->val);
            s.pop();
            p = p->right;
        }
    }
}

2.3、后序遍历

vector<int> posOrderUnRecur1(TreeNode* root) {
 		vector<int> path;
		 if(root == NULL)
		    return path;
		if (root != NULL) {
			stack<TreeNode*> s1 ;
			stack<TreeNode*> s2 ;
			s1.push(root);
			while (!s1.empty()) {
				root = s1.top();
				s1.pop();
				s2.push(root);
				if (root->left != NULL) {
					s1.push(root->left);
				}
				if (root->right != NULL) {
					s1.push(root->right);
				}
			}
			while (!s2.empty()) {
				TreeNode* tmp = s2.top();
				s2.pop();
				path.push_back(tmp->val);
			}
		}

3、二叉树之层遍历

层次遍历

void breadthFirstSearch(TreeNode* root){
    queue<TreeNode*> nodeQueue;
    nodeQueue.push(root);
    while (!nodeQueue.empty()) {
        root = nodeQueue.front();
        cout << root->data;
        nodeQueue.pop();
        if (root->lchild) {
            nodeQueue.push(root->lchild);     // 先把左子树入队
        }
        if (root->rchild) {
            nodeQueue.push(root->rchild);     // 再把右子树入队
        }
    }
}

把二叉树打印成多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
这里不就是层序遍历?可以采用上一题的解题策略,不过简单起见,将栈换成队列,并且没有方向之分,都是从左到右。

class Solution {
public:
        vector<vector<int> > Print(TreeNode* pRoot) {
            vector<vector<int> >result;
            if(pRoot == NULL)
                return result;
            queue<TreeNode*> q;
            q.push(pRoot);
            TreeNode* pHead;
            while(! q.empty())
            {
                vector<int>temp;
                int count = 0;
                int length = q.size();
                while((count++) < length)
                {
                     pHead = q.front();
                     temp.push_back(pHead->val);
                     q.pop();
                    if(pHead->left != NULL)
                        q.push(pHead->left);
                    if(pHead->right != NULL)
                        q.push(pHead->right);
                }
                result.push_back(temp);
            }
            return result;
        }
    
};

之字形打印二叉树

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
在这里插入图片描述

本题使用两个栈作为辅助容器。打印某一层全部节点时,把下一层的子节点保存到另一个栈内。如果当前打印的是奇数层,则先保存左子树节点再保存右子树节点到奇数栈内;如果当前打印的是偶数层,则先保存右子树在保存左子树节点到偶数栈内。
在这里插入图片描述

class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int> > result;
        if(pRoot == NULL)
            return result;
        stack<TreeNode*>odd_s;
        stack<TreeNode*>even_s;
        odd_s.push(pRoot);
        TreeNode* pHead;
        while(!odd_s.empty() || !even_s.empty())
        {
            vector<int>temp;
            if(!odd_s.empty())
            {
                while(!odd_s.empty())
                {
                    pHead = odd_s.top();
                    temp.push_back(pHead->val);
                    odd_s.pop();
                    if(pHead->left != NULL)
                        even_s.push(pHead->left);
                    if(pHead->right != NULL)
                        even_s.push(pHead->right);
                }
                result.push_back(temp);
            }
            else
            {
                while(!even_s.empty())
                {
                    pHead = even_s.top();
                    temp.push_back(pHead->val);
                    even_s.pop();
                    if(pHead->right != NULL)
                        odd_s.push(pHead->right);
                    if(pHead->left != NULL)
                        odd_s.push(pHead->left);
                }
                result.push_back(temp);
            }
        }
        return result;
    }
};

4、二叉树之深度相关

4.1、二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7]3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3 。


题目要求:给定一个二叉树,找出它的最大深度。 最大深度是指的从根节点一直到最远的叶节点中所有的节点数目。

题目分析:求二叉树的最大深度问题用到深度优先搜索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;
    }
};


==非递归==

```cpp
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root == NULL)
            return  0;
        int maxDeep = 0;
        queue <TreeNode*>q;
        //根节点入队
        q.push(root);
        while (!q.empty()) {
            int width = q.size();
            //每遍历一层深度+1
            maxDeep += 1;
            //注意这里循环的次数是width,出队的仅仅是每一层的元素
            for (int i = 0; i < width; i++) {
                TreeNode* nodeTemp = q.front();
                q.pop();
                if (nodeTemp->left != NULL) {
                    q.push(nodeTemp->left);
                }
                if(nodeTemp->right != NULL) {
                    q.push(nodeTemp->right);
                }
            }
        }
        return maxDeep;
    }
    
};

4.2、平衡二叉树

原题链接

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

示例 1:

给定二叉树 [3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7
返回 true 。

示例 2:

给定二叉树 [1,2,2,3,3,null,null,4,4]

       1
      / \
     2   2
    / \
   3   3
  / \
 4   4
返回 false 。


题目要求:求二叉树是否平衡,根据题目中的定义,高度平衡二叉树是每一个结点的两个子树的深度差不能超过1。

题目分析:我们肯定需要一个求各个点深度的函数,然后对每个节点的两个子树来比较深度差,时间复杂度为O(NlgN)

题目解答:

class Solution {
public:
    bool isBalanced(TreeNode* root) {
        if(root == NULL)
           return true;
        int left = TreeDepth(root->left);
        int right = TreeDepth(root->right);
        return abs(left -right) <= 1 &&
                isBalanced(root->left) &&
                isBalanced(root->right);
    }
    int TreeDepth(TreeNode* root)
    {
        if(root == NULL)
            return 0;
        return 1 + max(TreeDepth(root->left),TreeDepth(root->right));
    }
};

4.3、二叉树的直径


给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

 

示例 :
给定二叉树

          1
         / \
        2   3
       / \     
      4   5    
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

 

注意:两结点之间的路径长度是以它们之间边的数目表示。

题目要求:求二叉树的直径,并告诉了我们直径就是两点之间的最远距离。

题目分析:我们只要对每一个结点求出其左右子树深度之和,这个值作为一个候选值,然后再对左右子结点分别调用求直径对递归函数,这三个值相互比较,取最大的值更新结果res,因为直径不一定会经过根结点,所以才要对左右子结点再分别算一次。

题目解答:

class Solution {
public:
    int res = 0;
    int diameterOfBinaryTree(TreeNode* root) {
        diameterTree(root);
        return res;
    }
    int diameterTree(TreeNode* root) {
        if(root == NULL)
           return 0;
        int left = diameterTree(root->left);
        int right = diameterTree(root->right);
        res = max(res,left + right);
        return max(left,right) +1;
    }
};

4.4、二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回它的最小深度  2.


非递归做法

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root == NULL)
            return  0;
        int minDeep = 0;
        queue <TreeNode*>q;
        //根节点入队
        q.push(root);
        while (!q.empty()) {
            int width = q.size();
            //每遍历一层深度+1
            minDeep += 1;
            //注意这里循环的次数是width,出队的仅仅是每一层的元素
            for (int i = 0; i < width; i++) {
                TreeNode* nodeTemp = q.front();
                q.pop();
                if(nodeTemp->left == NULL && nodeTemp->right == NULL)
                    return minDeep;
                if (nodeTemp->left != NULL) {
                    q.push(nodeTemp->left);
                }
                if(nodeTemp->right != NULL) {
                    q.push(nodeTemp->right);
                }
                
            }
        }
        return minDeep;

    }
};


递归做法

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.5、二叉树的坡度

给定一个二叉树,计算整个树的坡度。

一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值。空结点的的坡度是0。

整个树的坡度就是其所有节点的坡度之和。

 

示例:

输入:
         1
       /   \
      2     3
输出:1

解释:
结点 2 的坡度: 0
结点 3 的坡度: 0
结点 1 的坡度: |2-3| = 1
树的坡度 : 0 + 0 + 1 = 1
 

提示:

任何子树的结点的和不会超过 32 位整数的范围。
坡度的值不会超过 32 位整数的范围。


class Solution {
public:
    int res = 0;
    int findTilt(TreeNode* root) {
       
       TreeSum(root) ;
       return res;

    }
    int TreeSum(TreeNode* root)//,int& res
    {
        if(root == NULL)
           return 0;
        int left = TreeSum(root->left);
        int right = TreeSum(root->right);
        res += abs(left - right);
        return (left + right + root->val);
    }
};

5、二叉树之侧视图相关

5.1、二叉树每一行最右边的一个数字

题目要求:这道题要求我们打印出二叉树每一行最右边的一个数字。

题目分析:实际上是求二叉树层序遍历的一种变形,我们只需要保存每一层最右边的数字即可,这道题只要在之前层遍历那道题上稍加修改即可得到结果,还是需要用到数据结构队列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;
    }
};

6、二叉树之递归应用

6.1、判断两棵树是否相同

题目要求:判断两棵树是否相同。

题目分析:利用深度优先搜索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);
    }
};

6.2、判断一棵树是否对称

题目要求:判断一棵树是否对称。
题目分析:利用深度优先搜索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);
    }
};

6.3、翻转二叉树

题目要求:这道题让我们翻转二叉树。
题目分析:利用三种方法求解问题。
题目解答:
class Solution {
public:
    TreeNode* invertTree1(TreeNode* root) {
        if(root  == NULL)
           return root;
        TreeNode* temp = root->left;
        root->left = root->right;
        root->right = temp;
        root->left = invertTree(root->left);
        root->right = invertTree(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* invertTree3(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;
    }
};

6.4、一个数是否是另一个树的子树

题目要求:这道题让我们求一个数是否是另一个树的子树。

题目分析:子树必须是从叶结点开始的,中间某个部分的不能算是子树,那么我们转换一下思路,是不是从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);
    }
};

参考

1、https://blog.csdn.net/pushup8/article/details/86014556

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值