BM32-40

BM32 合并二叉树

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
递归做法:

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param t1 TreeNode类 
     * @param t2 TreeNode类 
     * @return TreeNode类
     */
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        // write code here
        return mergeOper(t1,t2);
    }
    TreeNode* mergeOper(TreeNode* t1,TreeNode* t2){
        TreeNode* newTree;
        TreeNode* other;
        if((t1 == NULL)&&(t2 == NULL)){
            return NULL;
        }else{
            if(t1 == NULL){
                newTree = t2;
                return newTree;
            }else if(t2 == NULL){
                newTree = t1;
                return newTree;
            }else{
                newTree = t1;
                newTree->val += t2->val;
            }
            other = (newTree == t1)?t2:t1;
            newTree->left = mergeOper(newTree->left,other->left);
            newTree->right = mergeOper(newTree->right,other->right);
            return newTree;
        }
    }
};

思路解析:子问题,某两个对应位置结点t1,t2合并的四种情况:
(1)如果t1和t2均为空树,则合并后对应位置为空树NULL。
(2)如果t1为空树,t2不为空树,则合并后对应位置接t2。
(3)如果t2为空树,t1不为空树,则合并后对应位置接t1。
(4)如果t1,t2均不为空树,则合并后对应位置结点的值为t1->val + t2->val。
除此之外,为了尽可能少地分配空间,在原树上进行操作,减少空间复杂度。我们需判断这几种情况下t1和t2那棵树非空,非空的树用newTree来表示,另一棵树用other来表示:
(1)全为空,也就不用newTree和other了,直接return NULL。
(2)如果t1为空树,t2不为空树,newTree为t2,other为t1。
(3)如果t2为空树,t1不为空树,newTree为t1,other为t2。
(4)如果t1和t2均不为空树,则设newTree为t1,other为t2。
四种情况下,先分别找到newTree和other,按照上述分析合并,之后递归左右子树。

BM33 二叉树的镜像

在这里插入图片描述
在这里插入图片描述

/**
 * 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类 
     * @return TreeNode类
     */
    TreeNode* Mirror(TreeNode* pRoot) {
        // write code here
        if(pRoot != NULL){
            ChangeMirror(pRoot);
        }
        return pRoot;
    }
    void ChangeMirror(TreeNode* root){
        if(root->left == NULL && root->right == NULL){
            return;
        }else{
            if(root->left != NULL && root->right!=NULL){
                TreeNode* tmp = root->left;
                root->left = root->right;
                root->right = tmp;
                ChangeMirror(root->left);
                ChangeMirror(root->right);
            }else if(root->left == NULL && root->right!=NULL){
                root->left = root->right;
                root->right = NULL;
                ChangeMirror(root->left);
            }else{
                root->right = root->left;
                root->left = NULL;
                ChangeMirror(root->right);
            }
        }
    }
};

思路:递归方式,从根节点开始,分四种情况讨论。

BM34 判断是不是二叉搜索树

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return bool布尔型
     */
    bool isValidBST(TreeNode* root) {
        // write code here
        bool flag = true;
        TreeNode* cur = root;
        TreeNode* pre = NULL;
        stack<TreeNode*> s; 
        while(cur){
            s.push(cur);
            cur = cur->left;
        }
        while(!s.empty()||cur){
            while(cur){
                s.push(cur);
                cur = cur->left;
            }
            cur = s.top();
            if(pre!=NULL && cur->val <= pre->val){
                flag = false;
                break;
            }else{
                s.pop();
                pre = cur;
                cur = cur->right;
            }
        }
        return flag;
    }
};

思路:在二叉树的非递归中序遍历中改写visit(),在visit中判断pre->valval。

BM35 判断完全二叉树

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return bool布尔型
     */
    bool isCompleteTree(TreeNode* root) {
        // write code here
        if(root == NULL){
            return false;
        }else{
            bool flag = true;
            queue<TreeNode*> q;
            TreeNode* tmp;
            q.push(root);
            int count = q.size();
            int cmp_num = 1;
            while(!q.empty()){
                tmp = q.front();
                if(tmp->left && tmp->right){
                    q.pop();
                    q.push(tmp->left);
                    q.push(tmp->right);
                }else if(tmp->left == NULL && tmp->right!=NULL){
                    return false;
                }else if(tmp->right == NULL && tmp->left!=NULL){
                    q.pop();
                    q.push(tmp->left);
                    break;
                }else{
                    q.pop();
                    break;
                }
            }
            while(!q.empty()){
                tmp = q.front();
                q.pop();
                if(tmp->left!=NULL || tmp->right!=NULL){
                    return false;
                }
            }
            return true;
        }
    }
};

思路:完全二叉树有个重要的性质,当存在某个结点没有左子树但有右子树时,该树肯定不是完全二叉树。
判断完全二叉树,肯定要用到层序遍历。结合重要的性质,就有了突破口。具体分四种情况讨论:
1.当前结点有左孩子和右孩子,则当前结点出队列,左右孩子分别入队列。
2.当前结点无左孩子但有右孩子,存在这样的结点,直接能够证明一定不是完全二叉树。
3.当前结点有左孩子无右孩子,则当前结点出队列,左孩子入栈,跳出while循环。
4.当前结点无左右孩子,当前结点出队列,跳出while循环。
出了while循环后,应该保证:当前还在队列中的结点均为叶子结点,否则不是完全二叉树。

BM36 判断平衡二叉树

除了递归,实在想不出什么好办法。求出左右子树的高度,判断高度差,如果高度差绝对值大于1,则不是平衡二叉树,否则继续递归判断。

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

BM37 二叉搜索树的最近公共祖先

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param p int整型 
     * @param q int整型 
     * @return int整型
     */
    int lowestCommonAncestor(TreeNode* root, int p, int q) {
        // write code here
        while(true){
            if((p<=root->val && q>=root->val)||
              (p>=root->val && q<= root->val)){
                break;
            }else if(p<root->val && q<root->val){
                root = root->left;
            }else if(p>root->val && q>root->val){
                root = root->right;
            }   
        }
        return root->val;
    }
};

思路:从根节点开始,当根节点的值介于二叉树的某两个结点值中间时,就返回根节点的值;否则当当前根节点的值小于两个结点的值,就移向右子树,当当前根节点的值大于两个结点的值,就移向左子树。

BM 38 在二叉树中找公共祖先

在这里插入图片描述
所以节点值为5和节点值为1的节点的最近公共祖先节点的节点值为3,所以对应的输出为3。节点本身可以视为自己的祖先
本题为上一题的推广。

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param root TreeNode类 
     * @param o1 int整型 
     * @param o2 int整型 
     * @return int整型
     */
    int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
        // write code here
        stack<bool> route1 = findRoute(root,o1);
        stack<bool> route2 = findRoute(root,o2);
        stack<bool> mroute1;
        stack<bool> mroute2;
        while(!route1.empty()){
            mroute1.push(route1.top());
            route1.pop();
        }
        while(!route2.empty()){
            mroute2.push(route2.top());
            route2.pop();
        }
        while(!mroute1.empty()&&!mroute2.empty()){
            if(mroute1.top() == true && mroute2.top() == true){
                root = root->left;
            }else if(mroute1.top() == false && mroute2.top() == false){
                root = root->right;
            }else{
                break;   
            }
            mroute1.pop();
            mroute2.pop();
        }
        return root->val;
    }
    stack<bool> findRoute(TreeNode* root,int val){
        stack<bool> s1;
        stack<TreeNode*> s2;
        TreeNode* tmp = root;
        while(tmp){
            if(tmp->left){
                s1.push(true);   
            }
            s2.push(tmp);
            tmp = tmp->left;
        }
        while(!s2.empty()||tmp){
            while(tmp){
                if(tmp->left){
                    s1.push(true);   
                }
                s2.push(tmp);
                tmp = tmp->left;
            }
            tmp = s2.top();
            if(tmp->val == val){
                break;
            }else{
                s2.pop();
                if(tmp->right != NULL){
                    s1.push(false);   
                }else{
                    while(s1.top() == false){
                        s1.pop();
                    }
                    s1.pop();
                }
                tmp = tmp->right;
            }
        }
        return s1;
    }
};

思路:1)先找出5和1对应的从根节点开始的路径。用一个堆栈表示,如5为{左},1为{右},我们可以用true表示左,false表示右。相关操作可结合中序遍历二叉树完成。值得注意的思路是:当遍历到当前节点已无右子树且当前节点的值不为要找的值,则路径堆栈要将栈顶所有的false项和false项下的第一项true出栈,并转向上一个未遍历右孩子的父节点。
2)得到两个结点用堆栈表示的路径序列,就分别一个一个出栈,当发现一个节点的路径向左,另一个结点的路径向右时,就证明当前结点为最近公共祖先;当两个结点的当前路径均指向左,则指向当前结点的左孩子;当两个结点的当前路径均指向右,则指向当前结点的右孩子。

BM39 层序遍历序列化二叉树

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    char* Serialize(TreeNode *root) {  
        if(!root){
            return NULL;
        }
        string ret;
        queue<TreeNode*> q;
        TreeNode* tmp = root;
        q.push(tmp);
        int count = q.size();
        while(!q.empty()){
            tmp = q.front();
            if(tmp->val>=0){
                ret += to_string(tmp->val);
                ret += "&";
                if(tmp->left){
                    q.push(tmp->left);
                }else{
                    q.push(new TreeNode(-1));
                }
                if(tmp->right){
                    q.push(tmp->right);
                }else{
                    q.push(new TreeNode(-1));
                }
            }else{
                ret += "#&";
            }
            q.pop();
        }
        char* result = new char[ret.size()+1];
        strcpy(result,ret.c_str());
        return result;
    }
    TreeNode* Deserialize(char *str) {
        if(!str){
            return NULL;
        }
        string s(str);
        int index = 0;
        queue<TreeNode*> q;
        TreeNode* tmp;
        vector<string> v;
        while(index<=s.length()-1){
            if(str[index] == '#'){
                v.push_back("#");
                index += 2;
            }else{
                int count = index;
                while(str[count]!='&'){
                    count++;
                }
                v.push_back(s.substr(index,count-index));
                index = count+1;
            }
        }
        int i = 0;
        TreeNode* root = new TreeNode(stoi(v[i++],0,10));
        q.push(root);
        string m;
        while(i<v.size()){
            tmp = q.front();
            q.pop();
            m = v[i++];
            if(m == "#"){
                tmp->left = NULL;
            }else{
                TreeNode* addNew = new TreeNode(stoi(m,0,10));
                q.push(addNew);
                tmp->left = addNew;
            }
            
            m = v[i++];
            if(m == "#"){
                tmp->right = NULL;
            }else{
                TreeNode* addNew = new TreeNode(stoi(m,0,10));
                q.push(addNew);
                tmp->right = addNew;
            }
        }
        return root;
    }
};

思路:层序遍历的应用。

BM40 重建二叉树

根据中序和先序重建二叉树
递归方法,先序找根,中序分左右子树。

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.size() == 0){
            return NULL;
        }
        TreeNode* root = new TreeNode(pre[0]);
        int i=0;
        for(;i<vin.size();i++){
            if(vin[i] == pre[0]){
                break;
            }
        }
        vector<int> newPre1;
        newPre1.clear();
        newPre1.assign(pre.begin()+1,pre.begin()+1+i);
        vector<int> newPre2;
        newPre2.clear();
        newPre2.assign(pre.begin()+1+i,pre.begin()+pre.size());
        vector<int> newVin1;
        newVin1.clear();
        newVin1.assign(vin.begin(),vin.begin()+i);
        vector<int> newVin2;
        newVin2.clear();
        newVin2.assign(vin.begin()+1+i,vin.begin()+vin.size());
        root->left = reConstructBinaryTree(newPre1,newVin1);
        root->right = reConstructBinaryTree(newPre2,newVin2);
        return root;
    }        
};

BM41 输出二叉树的右视图

大意:先根据先序和中序重建二叉树,后输出右视图。所谓右视图,就是层序遍历每一层的最右一个结点。

vector<int> solve(vector<int>& xianxu, vector<int>& zhongxu) {
        // write code here
        TreeNode* root = buildTree(xianxu,zhongxu);
        queue<TreeNode*> q;
        q.push(root);
        TreeNode* tmp;
        int count = q.size();
        vector<int> result;
        while(!q.empty()){
            while(count--){
                tmp = q.front();
                q.pop();
                if(count == 0){
                    result.push_back(tmp->val);
                }
                if(tmp->left){
                    q.push(tmp->left);
                }
                if(tmp->right){
                    q.push(tmp->right);
                }
            }
            count = q.size();
        }
        return result;
    }

由于通过先序和中序构建二叉树的操作和BM40一模一样,所以封装成了函数buildTree,然后写一个层序遍历,在其中通过设定count变量,表示每层的结点数量,当节点数量还剩一个的时候,就添加到右视图中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值