二叉树相关练习(1)

重建二叉树

题目描述

给定节点数为 n 二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
在这里插入图片描述

解题思路
根据root节点,将中序vector划分成vin_left,vin_right两部分中序子序列 ;根据中序子序列长度,将前序vector划分成pre_left, pre_right对应的前序子序列 。
root->left递归生成 ,root->right递归生成。
前序遍历的第一个元素就是根节点,找到其在中序遍历序列中的位置,中序遍历序列中根节点位置的左半部分就是左子树,右半部分就是右子树,以此划分左右子树。不断缩小范围,当前序/中序开始位置下标大于结束位置下标时,上一次已经是叶子节点,以此作为递归出口。这里传入的下标是闭区间。

代码实现

class Solution {
public:
    TreeNode* reConstructBinaryTreeHelper(vector<int> pre,int pre_start,int pre_last,vector<int> vin,int vin_start,int vin_last){
        if(pre_start>pre_last || vin_start>vin_last)
            return nullptr;
        //创建根节点
        TreeNode* root=new TreeNode(pre[pre_start]);
        for(int i=vin_start;i<=vin_last;i++){
            if(vin[i]==pre[pre_start]){
                root->left=reConstructBinaryTreeHelper(pre, pre_start+1,pre_start+i-vin_start , vin,vin_start , i-1);
                root->right=reConstructBinaryTreeHelper(pre,pre_start+i-vin_start+1,pre_last, vin, i+1,vin_last);
                break;
            }
        }
        return root;
    }
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.empty() || vin.empty())
            return nullptr;
         
        return reConstructBinaryTreeHelper(pre,0,pre.size()-1,vin,0,vin.size()-1);
    }
};

判断树的子结构

题目描述

输入两棵二叉树A,B,判断B是不是A的子结构。(我们约定空树不是任意一个树的子结构)
假如给定A为{8,8,7,9,2,#,#,#,#,4,7},B为{8,9,2},2个树的结构如下,可以看出B是A的子结构
在这里插入图片描述

解题思路
二叉树都是递归定义的,所以递归操作是比较常见的做法 。
可以理解成子结构是原树的子树(或者一部分) ,也就是说,B要是A的子结构,B的根节点+左子树+右子树,都在A中存在且构成树形结构 。
比较的过程要分为两步 1. 先确定起始位置 。2. 在确定从该位置开始,后续的左右子树的内容是否一致

代码实现

class Solution {
public:
    bool IsSame(TreeNode* begin,TreeNode* begin_sub){
        if(begin_sub==nullptr)
            return true;
        if(begin==nullptr)
            return false;
        if(begin->val!=begin_sub->val)
            return false;
        
        return 
    }
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
        if(pRoot1==nullptr || pRoot2==nullptr)
            return false;
        bool result=false;
        if(pRoot1->val==pRoot2->val){
            result=IsSame(pRoot1, pRoot2);
        }
        if(!result){
            result=HasSubtree(pRoot1->left, pRoot2);
        }
        if(!result){
            result=HasSubtree(pRoot2->right, pRoot2);
        }
        
        return result;
    }
};

二叉树的镜像

题目描述

操作给定的二叉树,将其变换为源二叉树的镜像。
在这里插入图片描述在这里插入图片描述

解题思路
所谓的二叉树镜像本质是自顶向下(or自底向上)进行左右子树交换的过程 。

代码实现

class Solution {
public:
    void Swap(TreeNode* pRoot){
        if(pRoot==nullptr)
            return;
        TreeNode* tmp=pRoot->left;
        pRoot->left=pRoot->right;
        pRoot->right=tmp;
        
        Swap(pRoot->left);
        Swap(pRoot->right);
    }
    TreeNode* Mirror(TreeNode* pRoot) {
        if(pRoot==nullptr)
            return nullptr;
        Swap(pRoot);
        return pRoot;
    }
};

二叉树的层序遍历

题目描述

不分行从上往下打印出二叉树的每个节点,同层节点从左至右打印。例如输入{8,6,10,#,#,2,1},如以下图中的示例二叉树,则依次打印8,6,10,2,1(空节点不打印,跳过),请你将打印的结果存放到一个数组里面,返回。

解题思路
借助队列实现。

代码实现

class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        if(root==nullptr)
            return vector<int> ();
        vector<int> result;
        queue<TreeNode*> node;
        node.push(root);
        while(!node.empty()){
            TreeNode* father=node.front();
            node.pop();
            result.push_back(father->val);
            if(father->left!=nullptr){
                node.push(father->left);
            }
            if(father->right!=nullptr){
                node.push(father->right);
            }
        }
        
        return result;
    }
};

二叉树的后序遍历序列

题目描述

输入一个非空整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

解题思路
二叉搜索树:它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
BST的后序序列的合法序列是,对于一个序列S,最后一个元素是x (也就是root节点),如果去掉最后一个元素的序列为T,那么T满足:T可以分成两段,前一段(左子树)小于x,后一段(右子树)大于x,且这两段(子树)都是合法的后序序列 。
验证思路就是:当前序列,及其子序列必须都满足上述定义。

代码实现

class Solution {
public:
    bool VerifySquenceOfBSTHelper(vector<int> &sequence,int start,int end){
        if(start>=end)
            return true;
        int root=sequence[end];
        int i=start;
        while(i<end && sequence[i]<root){
            i++;
        }
        for(int j=i;j<end;j++){
            if(sequence[j]<root){
                return false;
            }
        }
        
        return VerifySquenceOfBSTHelper(sequence, start, i-1) &&
            VerifySquenceOfBSTHelper(sequence, i, end-1);
    }
    
    bool VerifySquenceOfBST(vector<int> sequence) {
        if(sequence.size()==0)
            return false;
        int end=sequence.size()-1;
        return VerifySquenceOfBSTHelper(sequence,0,end);
    }
};

二叉树中和为某一值的路径

题目描述:

输入一颗二叉树的根节点root和一个整数expectNumber,找出二叉树中结点值的和为expectNumber的所有路径。

解题思路:
这是一个典型的DFS回溯的算法。
回溯法本质是一个基于DFS的穷举的过程

  1. 先添加值
  2. 在判定现有结果是否满足条件
  3. DFS
  4. 回退

代码实现:

class Solution {
public:
    void FindPathHelper(TreeNode* root,int expectNumber,vector<vector<int>>& result,vector<int>& list){
        if(root==nullptr)
            return;
        list.push_back(root->val);
        expectNumber-=root->val;
        
        if(root->left==nullptr && root->right==nullptr && expectNumber==0){
            result.push_back(list);
        }
        FindPathHelper(root->left, expectNumber, result, list);
        FindPathHelper(root->right, expectNumber, result, list);
        
        list.pop_back();
    }
    
    vector<vector<int>> FindPath(TreeNode* root,int expectNumber) {
        vector<vector<int>> result;
        vector<int> list;
        FindPathHelper(root, expectNumber,result,list);
        return result;
    }
};

二叉树深度的判定

题目描述:

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度,根节点的深度视为 1 。

解题思路:

  1. 可以使用递归方式
  2. 可以层序遍历,统计层数,也就是深度or高度

代码实现:

class Solution {
public:
    void TreeDepthHelper(TreeNode* pRoot,int cur,int& max){
        if(pRoot==nullptr){
            if(max<cur){
                max=cur;
            }
            return;
        }
        
        TreeDepthHelper(pRoot->left, cur+1, max);
        TreeDepthHelper(pRoot->right, cur+1, max);
    }
    
    int TreeDepth(TreeNode* pRoot) {
        int depth=0,max=0;
        TreeDepthHelper(pRoot, depth, max);
        return max;
    }
};

按之字型打印二叉树

题目描述:

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

解题思路:
之字形打印,本质也是对树形结构的层序遍历,不过在遍历的过程中,需要更改遍历顺序。可以采用stack和queue的方式来进行处理。
核心思路:当前层从左向右遍历,那么下层就从left到right入栈,当前层如果从右向左遍历,那么下层就从right到left入栈。

代码实现:

class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int> > result;
        if(pRoot==nullptr)
            return result;
        queue<TreeNode*> q;
        stack<TreeNode*> st;
        vector<int> v;
        st.push(pRoot);//将第一层结点入栈
        int flag=1;//==1时从左向右遍历,入栈顺序从右向左
        while(!st.empty()){
            int size=st.size();
            //将本轮结点遍历并清空st
            for(int i=0;i<size;i++){
                TreeNode* cur=st.top();
                st.pop();
                v.push_back(cur->val);
                //将下层结点入队
                TreeNode* first = (flag==1) ? cur->left : cur->right;
                TreeNode* second = (flag==1) ? cur->right : cur->left;
                if(first) q.push(first);
                if(second) q.push(second);
            }
            result.push_back(v);
            //将下层入栈
            while(!q.empty()){
                st.push(q.front());
                q.pop();
            }
            //更改入栈顺序
            flag*=-1;
            v.clear();
        }
        
        return result;
    }
    
};

二叉搜索树中第k小的元素

题目描述:

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

解题思路:
BST本身就是有序的,中序遍历即是升序。要求第k小,即中序遍历时到达第k个元素(二叉搜索树,不存在两个相同的节点值)。此处,我们不使用递归,我们采用循环中序遍历的方式。

代码实现:

class Solution {
public:
    int kthSmallest(TreeNode* root, int k) {
        stack<TreeNode*> st;
        TreeNode* node = root;
        do{
            //把左子树全入栈
            while(node){
                st.push(node);
                node=node->left;
            }
            if(!st.empty()){
                node=st.top();
                st.pop();
                k--;
                if(k==0){
                    return node->val;
                }
                node=node->right;
            }
        }while(node || !st.empty());
        return 0;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值