剑指offer(六):二叉树上(cpp)

1.重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

class Solution {
public:
    TreeNode* rebuild(vector<int> &pre, int pres,int pred,vector<int> &vin,int vins,int vind){
        TreeNode *root = new TreeNode(pre[pres]);
        if(pres==pred && vins==vind && pre[pres]==vin[vins])
            return root;
        int leftlen = find(vin.begin()+vins,vin.begin()+vind+1,pre[pres])-(vin.begin()+vins);
        if(leftlen>0){      //有左子树在执行
            root->left = rebuild(pre,pres+1,pres+leftlen,vin,vins,vins+leftlen-1);
        }
        if(leftlen<pred-pres){//有右子树在执行
            root->right = rebuild(pre,pres+leftlen+1,pred,vin,vins+leftlen+1,vind);
        }
        return root;
    }
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.empty()||vin.empty()||pre.size()!=vin.size())
            return nullptr;
        TreeNode *root = rebuild(pre,0,pre.size()-1,vin,0,vin.size()-1);
        return root;
    }
};

2. 树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

class Solution {
public:
    bool DoesHave(TreeNode* p1,TreeNode* p2){
        if(p2==nullptr)
            return true;
        if(p1==nullptr)
            return false;
        if(p1->val != p2->val)
            return false;
        return DoesHave(p1->left,p2->left)&&DoesHave(p1->right,p2->right);
    }
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        bool res = false;
        if(pRoot1==nullptr||pRoot2==nullptr)
            return res;
        if(pRoot1->val == pRoot2->val)
            res = DoesHave(pRoot1,pRoot2);
        if(!res)
            res = HasSubtree(pRoot1->left,pRoot2);
        if(!res)
            res = HasSubtree(pRoot1->right,pRoot2);
        return res;
    }
};

3. 二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。

class Solution {
public:
    void Mirror(TreeNode *pRoot) {
        if(!pRoot || (pRoot->left==nullptr&&pRoot->right==nullptr))
            return;
        swap(pRoot->left,pRoot->right);
        if(pRoot->left)
            Mirror(pRoot->left);
        if(pRoot->right)
            Mirror(pRoot->right);
    }
};

4. 从上往下打印二叉树

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

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

5. 二叉搜索树的后序遍历序列

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

class Solution {
public:
    bool Istree(vector<int> &seq, int start,int end,int root){
        if(start == end)
            return true;
        auto iter = find_if(seq.begin()+start,seq.begin()+end,[root](int x){return x>root;});
        int len = iter-(seq.begin()+start);
        if(find_if(seq.begin()+start+len,seq.begin()+end,[root](int x){return x<root;})!=(seq.begin()+end))
            return false;
        bool left=true,right=true;
        if(len>0)
            left = Istree(seq,start,start+len-1,seq[start+len-1]);
        if(len<end-start)
            right = Istree(seq,start+len,end-1,seq[end-1]);
        return left&&right;
    }
    bool VerifySquenceOfBST(vector<int> sequence) {
        if(sequence.empty())
            return false;
        int len = sequence.size();
        bool res = Istree(sequence,0,len-1,sequence[len-1]);
        return res;
    }
};

6. 二叉树的深度

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

class Solution {
public:
    int TreeDepth(TreeNode* pRoot)
    {
        if(pRoot==nullptr)
            return 0;
        int lh = TreeDepth(pRoot->left);
        int rh = TreeDepth(pRoot->right);
        return 1+((lh>rh)?lh:rh);
    }
};

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

输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

class Solution {
    vector<vector<int>> res;
public:
    static bool compare(vector<int>& v1, vector<int>& v2){
        return v1.size()>v2.size();
    }
    void FindPath(TreeNode* root,int exnum,vector<int> &path,int csum){
        csum += root->val;
        path.push_back(root->val);
        if(root->left==nullptr&&root->right==nullptr&&csum==exnum)
            res.push_back(path);
        if(root->left)
            FindPath(root->left,exnum,path,csum);
        if(root->right)
            FindPath(root->right,exnum,path,csum);
        path.pop_back();
    }
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        if(root==nullptr)
            return res;
        vector<int> path;
        int csum = 0;
        FindPath(root,expectNumber,path,csum);
        sort(res.begin(),res.end(),compare);
        return res;
    }
};

活脱脱是二叉树前序遍历的有效使用,到达叶子节点之后若路径和与期待值相等就表示当前路径可取,否则返回上一层,注意取了引用的参数要手动回复上一层的值,值传递的不用管,如上面的csum变量。

8. 平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

  • 一、暴力递归,对每一个节点都进行一次比较高度求解若满足二叉平衡树的要求就继续向下递归,直到叶子节点。缺点是对好多节点进行了多次计算,优点是易于编码实现。
class Solution {
public:
    int TreeDepth(TreeNode* root){
        if(root==nullptr)
            return 0;
        int left = TreeDepth(root->left);
        int right = TreeDepth(root->right);
        return 1+(left>right?left:right);
    }
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot==nullptr)
            return true;
        int left = TreeDepth(pRoot->left);
        int right = TreeDepth(pRoot->right);
        if(left-right>1 || left-right<-1)
            return false;
        return IsBalanced_Solution(pRoot->left)&&IsBalanced_Solution(pRoot->right);
    }
};
  • 二、基于后序遍历处理,添加一个变量记录子树的深度,递归返回父节点的时候利用子节点的高度直接可得到父节点的深度。
class Solution {
public:
    bool IsBalanced(TreeNode* root, int& depth){
        if(root==nullptr){
            depth = 0;
            return true;
        }
        int left,right;
        if(IsBalanced(root->left,left)&&IsBalanced(root->right,right)){
            if(left-right<=1&&left-right>=-1){
                depth = 1+(left>right?left:right);
                return true;
            }
        }
        return false;
    }
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot==nullptr)
            return true;
        int pDepth;
        return IsBalanced(pRoot,pDepth);
    }
};

9. 二叉树的下一个结点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode==nullptr)
            return nullptr;
        TreeLinkNode* pNext;
        if(pNode->right){
            TreeLinkNode* right = pNode->right;
            while(right->left){
                right = right->left;
            }
            pNext = right;
        }else if(pNode->next){
            TreeLinkNode* current = pNode;
            TreeLinkNode* parent = pNode->next;
            while(parent!=nullptr&&current==parent->right){
                current = parent;
                parent = parent->next;
            }
            pNext = parent;
        }
        return pNext;
    }
};

考虑问题要全面,分清主次,三种情况:

  • 有右子树,找到右子树的最左边的节点
  • 无右子树,但本身是左节点直接返回父节点
  • 既无右子树,本身还是右子树就向上寻找直到节点的某个祖先节点为其父的左子树节点的时候,返回这个祖先的父节点。

10.对称的二叉树

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

class Solution {
public:
    bool Issame(TreeNode* root1,TreeNode* root2){
        if(root1==nullptr&&root2==nullptr)
            return true;
        if(root1==nullptr || root2==nullptr)
            return false;
        if(root1->val != root2->val)
            return false;
        return Issame(root1->left,root2->right)&&Issame(root1->right,root2->left);
    }
    bool isSymmetrical(TreeNode* pRoot)
    {
        return Issame(pRoot,pRoot);
    }

};

这个递归用的太秒了,虽然本质上仍然是前序遍历,除此之外还可以用作判断两棵树是否为同一棵树

11. 按之字形顺序打印二叉树

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

class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int> > res;
        if(pRoot==nullptr)
            return res;
        stack<TreeNode*>list[2];
        int current = 0;
        int next = 1;
        vector<int> path;
        list[current].push(pRoot);
        while(!list[0].empty()||!list[1].empty()){
            TreeNode* tmp = list[current].top();
            path.push_back(tmp->val);
            list[current].pop();
            if(current==0){
                if(tmp->left)
                    list[next].push(tmp->left);
                if(tmp->right)
                    list[next].push(tmp->right);
            }else {
                if(tmp->right)
                    list[next].push(tmp->right);
                if(tmp->left)
                    list[next].push(tmp->left);
            }
            if(list[current].empty()){
                current = 1-current;
                next = 1-next;
                res.push_back(path);
                path.erase(path.begin(),path.end());
            }
        }
        return res;
    }
};
发布了39 篇原创文章 · 获赞 7 · 访问量 4383
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章