剑指offer<数据结构>---------------------二叉树

309 阅读7分钟

二叉树的深度

题目来源牛客网

1、问题描述

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度,根节点的深度视为 1 。 数据范围:节点的数量满足 0 le nle 1000≤n≤100 ,节点上的值满足 0 \le val \le 1000≤val≤100
进阶:空间复杂度 O(1)O(1) ,时间复杂度 O(n)O(n) 假如输入的用例为{1,2,3,4,5,#,6,#,#,7},那么如下图:

image.png

2、思路解析

对于每一个节点都判断是不是为NULL,为NULL就直接返回节点数0
然后递归分别计算左右子树的最大深度
最后结果取左右子树的最大深度加一

image.png

3、代码实现

struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    int TreeDepth(TreeNode* root) {
        if(root==NULL){
            return  0;
        }
        //取子树最大的一边
        return max(TreeDepth(root->left)+1,TreeDepth(root->right)+1);
    
    }
};

按之字形顺序打印二叉树

题目来源牛客网

1、问题描述

给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)

数据范围:0 \le n \le 15000≤n≤1500,树上每个节点的val满足 |val| <= 1500∣val∣<=1500
要求:空间复杂度:O(n)O(n),时间复杂度:O(n)O(n)

例如:
给定的二叉树是{1,2,3,#,#,4,5}

image.png

2、思路解析

思路一:双栈+广度优先遍历
定义两个栈一个为正向栈,一个为反向栈,首先将头节点插入到正向栈中,开始广度优先遍历,取正向栈的大小遍历正向栈,将栈中节点数值插入到数组中将左子节点和右子节点按顺序插入到反向栈中。将数组保存在二维数组中。然后又遍历反向栈先将出栈节点的数值插入到数组中,把节点的右子节点、左子节点按顺序插入到正向栈中,然后直到反向栈为NULL,最后讲数组保存在二维数组中。直到遍历完二叉树。

image.png

image.png

image.png

image.png

3、代码实现

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    //层序遍历
    //广度优先遍历
    vector<vector<int> > Print(TreeNode* proot) {
          vector<vector<int> >  v;
        if(proot==NULL){
            return v;
        }
        stack<TreeNode*>q;
        stack<TreeNode*>p;
        q.push(proot);
        while(!q.empty()){
            vector<int> vm;
            int size=q.size();
            while(size--){
                TreeNode*root=q.top();
                q.pop();
                vm.push_back(root->val);
                if(root->left){
                    p.push(root->left);
                }
                if( root->right){
                    p.push(root->right);
                }

            }
            if(!vm.empty()){
                v.push_back(vm);
                vm.clear();
            }
            
            int size2=p.size();
            while(size2--){
                TreeNode*root=p.top();
                p.pop();
                vm.push_back(root->val);
                //插入反向栈
                if(root->right){
                    q.push(root->right);
                }
                if(root->left){
                    q.push(root->left);
                }
            }
                   if(!vm.empty()){
                    v.push_back(vm);
                    vm.clear();
                    } 
            }
        return  v;
        
        
    }
    
};

二叉搜索树的第k个节点

题目来源牛客网

1、问题描述

给定一棵结点数为n 二叉搜索树,请找出其中的第 k 小的TreeNode结点值。

1.返回第k小的节点值即可

2.不能查找的情况,如二叉树为空,则返回-1,或者k大于n等等,也返回-1

3.保证n个节点的值不一样

数据范围: 0 \le n \le10000≤n≤1000,0 \le k \le10000≤k≤1000,树上每个结点的值满足0 \le val \le 10000≤val≤1000
进阶:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)\

如输入{5,3,7,2,4,6,8},3时,二叉树{5,3,7,2,4,6,8}如下图所示:

image.png

2、思路解析

思路一:保存搜索树的节点 先了解一下二叉搜索树的一些特性,二叉搜索树实际是一个排序树,中序序遍历是一个有序数组,因为要求搜索树的第k大节点,所以中序遍历讲二叉搜索树节点保存到数组中,最后直接返回数组的ans[k-1]就行 思路二:递归 每次递归时将节点数++,直到遇到节点数为K的将root节点数值赋给ans,当遍历完搜索树时返回结构ans

3、代码实现

 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
    vector<int> v;
    
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    //中序遍历
    void _KthNode(TreeNode*root){
        if(root==NULL){
            return;
        }
        _KthNode(root->left);
        v.push_back(root->val);
        _KthNode(root->right);
        
        
    }
    int KthNode(TreeNode* proot, int k) {
        // write code here
        if(proot==NULL||k==0){
            return -1;
        }
        _KthNode(proot);
        if(k>v.size()){
            return -1;
        }
        return v[k-1];
    }
};
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    int count=0;//标记节点数
    int ans=-1;
    int KthNode(TreeNode* root, int k) {
        // write code here
        if(root==NULL){
            return -1;
        }

        //遍历左子树
        KthNode(root->left, k);
             count++;
        //判断是不是到达第k个节点
        if(count==k)   return ans=root->val; 
        //遍历右子树
        KthNode(root->right, k);
        return ans;
    }
};
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    int count=0;//标记节点数
    int ans=-1;
    int KthNode(TreeNode* root, int k) {
        // write code here
        if(root==NULL){
            return -1;
        }

        //遍历左子树
        KthNode(root->left, k);
             count++;
        //判断是不是到达第k个节点
        if(count==k)   return ans=root->val; 
        //遍历右子树
        KthNode(root->right, k);
        return ans;
    }
};

重建二叉树

题目来源牛客网

1、问题描述


给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。

image.png

提示:

1.vin.length == pre.length

2.pre 和 vin 均无重复元素

3.vin出现的元素均出现在 pre里

4.只需要返回根结点,系统会自动输出整颗树做答案对比

数据范围:n \le 2000n≤2000,节点的值 -10000 \le val \le 10000−10000≤val≤10000

要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)

2、思路解析

已知二叉树的前序序列第一个元素就是二叉树的根节点,所以先构造子节点,然后找到中序中根节点的位置(中序序列中根节点的左右数据元素就是根节点左右子树节点的数值),将中序序列分为左右两个子树的中序序列,删除前序序列的第一个元素,第二个元素就是左子树的根节点元素,所以最后递归构建root的左子树和右子树。

3、代码实现

 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

//已知前序遍历第一个数组为根节点
class Solution {
public:
    int index=0;
     TreeNode* _reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(vin.empty()){
            return NULL;
        }
        //先构造根节点  前序遍历第一个数据为根节点数据
        TreeNode*root=new TreeNode(pre[index]);
        
        
        //找到中序序列的根节点位置
        int mid=find(vin.begin(),vin.end(),pre[index])-vin.begin();
        //删除前序序列第一个数据
        index++;
        //分割中序序列构造左子树和右子树
        vector<int> left(vin.begin(),vin.begin()+mid);
        root->left=_reConstructBinaryTree(pre,left);
        vector<int> right(vin.begin()+mid+1,vin.end());
        root->right=_reConstructBinaryTree(pre,right);
        return root;
    }
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
       return  _reConstructBinaryTree(pre,vin);
        
    }
};

树的子结构

题目来源:牛客网

1、问题描述

image.png

2、思路解析

层序遍历二叉树root1当遇到和root2根节点数组相等的节点就调用相同二叉树函数判断是不是root1的子树,当返回为false时就证明不是这个点为节点的子树,继续层序遍历,当有遇到跟root2根节点相同的节点时继续判断子树是不是相同二叉树,如果是就直接返回true,如果还不是就继续遍历root1.直到遍历结束。

3、代码实现

struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    bool _HasSubtree(TreeNode* root1, TreeNode* root2){
        if(root2==NULL){
            return true;
        }
        if(root1==NULL&&root2!=NULL){
            return false;
        }
        if(root1->val!=root2->val){
            return false;
        }
        //左子树&&右子树
        return _HasSubtree(root1->left,root2->left)
            &&_HasSubtree(root1->right,root2->right);
    }
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
        if(pRoot1==NULL&&pRoot2==NULL){
            return false;
        }
        if(pRoot1==NULL){
            return false;
        }
        if(pRoot2==NULL){
            return false;
        }
        
        
        
        //层序遍历找到该节点
        queue<TreeNode*>q;
        q.push(pRoot1);
        while(!q.empty()){
            int size=q.size();
            while(size--){
                TreeNode*root=q.front();
                q.pop();
                //根节点判断
                if(root->val==pRoot2->val){
                    if(_HasSubtree(root,pRoot2)){
                        return true;
                    }
                    //没有找到到下一层寻找
                }
                if(root->left){
                    q.push(root->left);
                }
                if(root->right){
                    q.push(root->right);
                }
                
            }
            
        }
        return false;

    }
};