二叉树递归

递归函数多次返回,返回给主函数的是第一调用递归函数时的状态,其它深层的递归返回给上一层状态

面试题27. 二叉树的镜像

class Solution {
public:
    TreeNode* mirrorTree(TreeNode* root) {
        if(root) {
            TreeNode* lr = mirrorTree(root->left);
            TreeNode* ri = mirrorTree(root->right);
            root->left = ri;
            root->right = lr;
        }
        return root;
    }
};

不同的二叉搜索树

结题思路:假设n个节点存在二叉排序树的个数是G(n),1为根节点,2为根节点,…,n为根节点,当1为根节点时,其左子树节点个数为0,右子树节点个数为n-1,同理当2为根节点时,其左子树节点个数为1,右子树节点为n-2,所以可得
G(n) = G(0)*G(n-1)+G(1)*(n-2)+...+G(n-1)*G(0)

class Solution {
public:
    int numTrees(int n) {
        if(n<=2) return n;
        vector<int> dp(n+1,0);
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 2;
        //dp[3] = d[0]*d[2] + d[1]*d[1] + d[2]*d[0]
        for(int i=3;i<=n;i++)
            for(int j=0;j<i;j++)
                dp[i] += dp[j]*dp[i-j-1];
        return dp[n];
    }
};


113 路径总和 II


class Solution {
public:
    
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> res;
        vector<int> tmp;
        if(!root) return res;
        
        if(root->val==sum && !root->left && !root->right){
            tmp.push_back(root->val);
            res.push_back(tmp);
            return res;
        }
        
        vector<vector<int>> lefts = pathSum(root->left,sum-root->val);
        for(int i =0;i<lefts.size();i++){
        // 把父节点 追加到vector<> 的前面,
            lefts[i].insert(lefts[i].begin(),root->val);
            res.push_back(lefts[i]);
        }
        
        vector<vector<int>> rights = pathSum(root->right,sum-root->val);
        for(int i =0;i<rights.size();i++){
            rights[i].insert(rights[i].begin(),root->val);
            res.push_back(rights[i]);
        }
        
        return res;
    }
    
};


// 解法2 深度递归遍历

    void dfs(TreeNode* root, int sum,vector<int>& tmp,vector<vector<int>>& res){
        if(!root) return ;
        
        tmp.push_back(root->val);
        if(sum==root->val && !root->left && !root->right){
            res.push_back(tmp);
        }
        
        dfs(root->left,sum-root->val,tmp,res);
        dfs(root->right,sum-root->val,tmp,res);
        tmp.pop_back();
           
    }
    
    
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> res;
        vector<int> tmp;
        if(!root) return res;
        dfs(root,sum,tmp,res);
        return res;
    }

129. 求根到叶子节点数字之和

class Solution {
public:
    void dfs(TreeNode* root,int cnt,vector<int>& tmp){
        if(!root) return ;
        if(!root->left && !root->right){
            tmp.push_back(cnt*10+root->val);
        }
        dfs(root->left,cnt*10+root->val,tmp);
        dfs(root->right,cnt*10+root->val,tmp);
    }
    
    
    int sumNumbers(TreeNode* root) {
       int res = 0;
        if(!root) return res;
        vector<int> tmp;
        dfs(root,0,tmp);
        
        for(auto i:tmp)
            res+=i;
        
        return res;
    }
};

124. 二叉树中的最大路径和

在这里插入图片描述

class Solution {
public:
   int res;
   int pathSum(TreeNode* root){
    if(!root) return 0;
    int left = max(pathSum(root->left),0);
    int right = max(pathSum(root->right),0);
    res = max(res,root->val+left+right);
    return root->val+max(0,max(left,right));
    }


int maxPathSum(TreeNode* root) {
    if(!root) return 0;
    res = root->val;
    pathSum(root);
    return res;
    }
};

404- 左叶子之和(easy)

 计算给定二叉树的所有左叶子之和。
   3
   / \
  9  20
    /  \
   15   7

在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
 void dfs(TreeNode* root,int& sum,bool flag){
        if(!root) return ;
        if(flag && !root->left && !root->right)
            sum+=root->val;
        dfs(root->left,sum,true);
        dfs(root->right,sum,false);
    }
    
    
    int sumOfLeftLeaves(TreeNode* root) {
        int sum = 0;
        if(!root) return 0;
        dfs(root,sum,false);
        return sum;
    }

// 解法2

int res = 0;
int sumOfLeftLeaves(TreeNode* root) {
    int sum = 0;
    if(!root) return 0;
    
    if(root->left != NULL && root->left->left == NULL && root->left->right == NULL)
        res += root->left->val;
    sumOfLeftLeaves(root->left);
    sumOfLeftLeaves(root->right);
    return  res;
}

// 解法3  return 理解
// res累加,是给首次调用函数return用的,如果
int sumOfLeftLeaves(TreeNode* root) {
  if(root == null) return 0;
  int res = 0;
  //判断节点是否是左叶子节点,如果是则将它的和累计起来
  if(root.left != null && root.left.left == null && root.left.right == null){
      res += root.left.val;
  }
  return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right) + res;
}

513. 找树左下角的值()

给定一个二叉树,在树的最后一行找到最左边的值。

注意:是树最后一行最左边的值,不是最后一行最左子树的值
可以使用层次遍历,取每一层第一个元素,然后深度每加一层,更新一次最左的元素

    int findBottomLeftValue(TreeNode* root) {
        if(!root) return 0;
        queue<TreeNode*> pq;
        pq.push(root);
        TreeNode* res;
        
        while(!pq.empty()){
            int len = pq.size();
            for(int i=0;i<len;i++){
                TreeNode* node = pq.front();
                pq.pop();
                
                if(i==0) res = node;
                if(node->left)
                    pq.push(node->left);
                if(node->right)
                    pq.push(node->right);   
            }  
        }
        return res->val;
    }

297. 二叉树的序列化与反序列化


class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if(!root) return "#_";
        string res = to_string(root->val)+'_';
        res += serialize(root->left);
        res += serialize(root->right);
        return res;
    }
    
    TreeNode* deserialize(string data) {
        if(data == "") return nullptr;
        queue<string> mq;
        stringstream ss(data);
        string item;

        while(getline(ss,item,'_'))
            mq.push(item);

        return help(mq);
    }

    TreeNode* help(queue<string>& mq){
        // if(mq.empty()) return ;
        string tmp = mq.front();
        mq.pop();
        if(tmp == "#") return nullptr;
        TreeNode* head = new TreeNode(stoi(tmp));
        head->left = help(mq);
        head->right = help(mq);
        return head;
    }

};

// 层序遍历

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        string res = "";
        if(!root) return res;
        queue<TreeNode*> mq;
        mq.push(root);
        while(!mq.empty()){
            int size = mq.size();
            for(int i=0;i<size;i++){
                TreeNode* cur = mq.front();
                mq.pop();
                if(cur==nullptr){
                    res += "#_";
                }else{    
                    res += to_string(cur->val) + '_';
                    mq.push(cur->left);
                    mq.push(cur->right);
                }
            }
        }
        return res;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if(data == "") return nullptr;
        queue<TreeNode*> mq;
        stringstream ss(data);
        string item;
        vector<string> pre;
        while(getline(ss,item,'_'))
            pre.push_back(item);
        
        TreeNode* root = new TreeNode(stoi(pre[0]));
        mq.push(root);
        int i=1;
        while(!mq.empty()){
            TreeNode* cur = mq.front();
            mq.pop();
            if(cur==nullptr) continue;
            cur->left = pre[i]!="#"?new TreeNode(stoi(pre[i])):nullptr;
            cur->right = pre[i+1]!="#"?new TreeNode(stoi(pre[i+1])):nullptr;
            i+=2;
            mq.push(cur->left);
            mq.push(cur->right);
        }
        return root;
    }
};


面试题68 - I. 二叉搜索树的最近公共祖先

在这里插入图片描述

  • 由于给定我们的是二叉搜索树,我们要利用好这个特性,知道二叉搜索树的特性是位于左子树的节点都比父节点小,位于右子树的节点都比父节点大

  • 更具这个特性我们从根节点开始遍历,从上到下找到第一个在两个输入节点值之间的节点就是最近的公共祖先

  • 如果当前节点的值比给定两个节点的值都小,那么可以肯定的是公共祖先一定存在于当前节点的右子树中,继续在右子树中寻找

  • 如果当前节点的值比给定两个节点的值都大,那么可以肯定的是公共祖先一定存在于当前节点的左子树中,继续在左子树中寻找

  • 如果当前节点的值在给定两个节点之间,这就是我们要找的公共祖先,返回即可


class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root) return root;
        // 都在左子树 或者 右子树上, 则继续向下递归查找
        if(root->val > p->val && root->val > q->val){
           return lowestCommonAncestor(root->left,p,q);
        }else if(root->val < p->val && root->val < q->val){
           return lowestCommonAncestor(root->right,p,q);
        }
        return root;
    }
};

105 从前序与中序遍历序列构造二叉树

主要是定位 左右子树的 区间信息,然后 递归构建 左右子树即可

class Solution {
public:
    TreeNode* dfs(vector<int> pre, vector<int> ino,int pl,int pr,int il,int ir){
        if (pl > pr || il > ir) return nullptr;
        TreeNode *root = new TreeNode(pre[pl]);
        int rootin = il;
        while(rootin<=ir && ino[rootin]!=pre[pl]) rootin++;
        int left = rootin - il;
        root->left = dfs(pre,ino,pl+1,pl+left,il,rootin-1);
        root->right = dfs(pre,ino,pl+left+1,pr,rootin+1,ir);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.empty()) return nullptr;
        return dfs(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
    }
};

另一种写法

TreeNode* make(vector<int>& pre, vector<int>& ino,int pl,int pr,int il,int ir){
    if(pl > pr || il > ir) return nullptr;
    TreeNode* root = new TreeNode(pre[pl]);

    // int rootin = il;
    // while (rootin <= ir && ino[rootin] != pre[pl]) rootin++;
    
    int rootin = -1;
    for(int i=il;i<=ir;i++)
        if(pre[pl] == ino[i]){
            rootin = i;
            break;
        }

    int len = rootin - il;
    root->left = make(pre,ino,pl+1,pl+len,il,rootin-1);
    root->right = make(pre,ino,pl+len+1,pr,rootin+1,ir);
    return root;
}


TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    if(preorder.size() < 1) return nullptr;
    return make(preorder,inorder,0,preorder.size()-1,0,preorder.size()-1);
}

889. 根据前序和后序遍历构造二叉树

和上面的思路类似, 定位 左右子树的区间,然后递归构建子树

TreeNode* make(vector<int>& pre, vector<int>& post,int lo1,int lo2,int n){
    if( n==0 ) return nullptr;
    TreeNode* root = new TreeNode(pre[lo1]);
    if( n==1 ) return root;

    int leftin = -1;
    for(int i=lo2;i<post.size();i++)
        if (post[i] == pre[lo1+1]){
            leftin = i;
            break;
        }
    int len = leftin - lo2 + 1;
    root->left = make(pre,post,lo1+1,lo2,len);
    root->right = make(pre,post,lo1+len+1,lo2+len,n-len-1);
    return root;
}


// 889. 根据前序和后序遍历构造二叉树
TreeNode* constructFromPrePost(vector<int>& pre, vector<int>& post) {
    return make(pre,post, 0, 0, pre.size());
}

108 升序构建二叉搜索树

区间分治类的题目,使用左闭右闭区间

class Solution {
public:
    // 左闭右闭区间  比较理想
    TreeNode* help(vector<int>& nums,int left,int right){
        if(left>right) return nullptr;
        int mid = (right+left)/2;
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = help(nums,left,mid-1);
        root->right = help(nums,mid+1,right);
        return root;
    }

    TreeNode* sortedArrayToBST(vector<int>& nums) {
        if(nums.empty()) return nullptr;
        return help(nums,0,nums.size()-1);
    }
};

/*
左闭右开
if(l>=r)//等号必须取到,只取等号也可以
int mid=(l+r)/2;
//区间为[l,mid],[mid+1,r],但不能是[l,mid-1],[mid,r],因为mid取不到,如果区间设为[l,mid-1],则会少一个mid-1的元素  因为右开
root->left=build(st,l,mid);
root->right=build(st,mid+1,r);
return build(nums,0,nums.size());//右一位
*/

222. 二叉树的节点数

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root) return 0;
        int lr = countNodes(root->left);
        int ri = countNodes(root->right);
        return (lr+ri)+1;
    }
};


// 最小 大深度
class Solution {
public:
    int minDepth(TreeNode* root) {
        if(!root) return 0;
        int lde = minDepth(root->left);
        int rde = minDepth(root->right);
        return min(lde,rde)+1;
    }
};

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(!root) return 0;
        int lde = minDepth(root->left);
        int rde = minDepth(root->right);
        return (lde,rde)+1;
    }
};

563. 二叉树的坡度

class Solution {
public:
    int help(TreeNode* root,int& res){
        if(!root) return 0;
        int lr = help(root->left,res);
        int ri = help(root->right,res);
        res += abs(lr-ri);
        return root->val+lr+ri;
    }
    int findTilt(TreeNode* root) {
        int res = 0;
        help(root,res);
        return res;
    }
};

572. 另一个树的子树

c++ 先在主串中找到 t的头结点,然后从这里开始找是否满足子树,不满足,则继续在主串中查找, 满足 则退出

class Solution {
public:
    bool help(TreeNode* a,TreeNode* b){
        if(a==nullptr && b==nullptr) return true;
        if(!a || !b) return false;
        if(a->val != b->val) return false;
        return help(a->left,b->left) && help(a->right,b->right);
    }

    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(!s) return false;
        if(s->val == t->val){
            bool tmp = help(s,t);
            if(tmp) return true;
        }
        return isSubtree(s->left,t) || isSubtree(s->right,t);
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值