树常见题目总结

1.树的前序遍历

递归:

class Solution {
public:
   vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ans;
        preorder(ans,root);
        return ans;
    }
    void preorder(vector<int> &ans,TreeNode* root)
    {
        if(root == NULL)
            return;
        ans.push_back(root->val);
        preorder(ans,root->left);
        preorder(ans,root->right);
    }
};

非递归:

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


2.中序遍历

递归:

class Solution {
public:
    vector<int>inorderTraversal(TreeNode* root){
        vector<int>res;
        inorder(root,res);
        return res;
    }
    void inorder(TreeNode* root,vector<int>& res){
        if(root == NULL){
            return;
        }
        inorder(root -> left,res);
        res.push_back(root -> val);
        inorder(root -> right,res);
    }
};

非递归:

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*>tmp;
        while(root != NULL || !tmp.empty()){
            if(root != NULL){
                tmp.push(root);
                root = root -> left;
            }
            else{
                root = tmp.top();
                res.push_back(root -> val);
                tmp.pop();
                root = root -> right;
            }
        }
        return res;
    }
};

3.后序遍历

递归:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root){
        vector<int>res;
        postorder(res,root);
        return res;
    }
    void postorder(vector<int> &res,TreeNode* root){
        if(root == NULL){
            return;
        }
        postorder(res,root -> left);
        postorder(res,root -> right);
        res.push_back(root -> val);
    }
};

非递归:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> tmp1;
        stack<TreeNode*> tmp2;
        if(root != NULL){
            tmp1.push(root);
            while(!tmp1.empty()){
                    root = tmp1.top();
                    tmp2.push(tmp1.top());
                    tmp1.pop();
                    if(root -> left != NULL)
                        tmp1.push(root -> left);
                    if(root -> right != NULL)
                        tmp2.push(root -> right);
                }
            }
            while(!tmp2.empty()){
                res.push_back(tmp2.top() -> val);
                tmp2.pop();
            }
        return res;
    }
};

4.重建二叉树

题目描述:

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

实现代码:

class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.size() == 0){                    //如果为空,返回NULL
            return NULL;
        }
        //依次是前序遍历左子树,前序遍历右子树,中序遍历左子树,中序遍历右子树
        vector<int> left_pre, right_pre, left_vin, right_vin;
        //中序遍历第一个节点一定为根节点
        TreeNode* head = new TreeNode(pre[0]);
        //找到中序遍历的根节点
        int root = 0;
        //遍历找到中序遍历根节点索引值
        for(int i = 0; i < pre.size(); i++){
            if(pre[0] == vin[i]){
                root = i;
                break;
            }
        }
           //利用中序遍历的根节点,对二叉树节点进行归并
        for(int i = 0; i < root; i++){
            left_vin.push_back(vin[i]);
            left_pre.push_back(pre[i + 1]);            //前序遍历第一个为根节点
        }
        
        for(int i = root + 1; i < pre.size(); i++){
            right_vin.push_back(vin[i]);
            right_pre.push_back(pre[i]);
        }
        
        //递归,再对其进行上述所有步骤,即再区分子树的左、右子子数,直到叶节点
        head->left = reConstructBinaryTree(left_pre, left_vin);
        head->right = reConstructBinaryTree(right_pre, right_vin);
        return head;
    }
};

5.树的子结构

题目描述:
输入两颗二叉A,B,判断B是不是A的子结构。(PS:我们约定空树不是任意一个树的子结构)。
实现代码:
class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        bool result = false;
        if(pRoot1 != NULL && pRoot2 != NULL){
            if(pRoot1->val == pRoot2->val){
            result = DoesTree1HasTree2(pRoot1, pRoot2);
        }
            if(!result){
                result = HasSubtree(pRoot1->left, pRoot2);
            }
            if(!result){
                result = HasSubtree(pRoot1->right, pRoot2);
            }
        }
        return result;
    }
private:
    bool DoesTree1HasTree2(TreeNode* pRoot1, TreeNode* pRoot2){
        if(pRoot2 == NULL){
            return true;
        }
        if(pRoot1 == NULL){
            return false;
        }
        if(pRoot1->val != pRoot2->val){
            return false;
        }
        return DoesTree1HasTree2(pRoot1->left, pRoot2->left) && DoesTree1HasTree2(pRoot1->right, pRoot2->right);
    }
};

6.二叉树的镜像

题目描述:

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

如下图所示:

剑指Offer(十八):二叉树的镜像实现代码:

class Solution {
public:
    void Mirror(TreeNode *pRoot) {
        if((pRoot == NULL) || (pRoot->left == NULL && pRoot->right == NULL)){
            return;
        }
        
        //交换根节点的左右结点
        TreeNode *pTemp = pRoot->left;
        pRoot->left = pRoot->right;
        pRoot->right = pTemp;
        
        //递归左子树
        if(pRoot->left){
            Mirror(pRoot->left);
        }
        //递归右子树
        if(pRoot->right){
            Mirror(pRoot->right);
        }
    }
};

7.从上往下打印二叉树

题目描述:
从上往下打印出二叉的每个节点,同层节点从左至右打印。
实现代码:
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        TreeNode* fr;
        if(root == NULL){
            return result;
        }
        que.push(root);
        while(!que.empty()){
            fr = que.front();
            result.push_back(fr->val);
            if(fr->left != NULL){
                que.push(fr->left);
            }
            if(fr->right != NULL){
                que.push(fr->right);
            }
            que.pop();
        }
        return result;
    }
private:
    vector<int> result;
    queue<TreeNode*> que;
};

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

题目描述:
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
实现代码:
class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber){
        if(root == NULL){
            return result;
        }
        
        tmp.push_back(root->val);
        if((expectNumber - root->val ) == 0 && root->left == NULL && root->right == NULL){
            result.push_back(tmp);
        }
        
        //遍历左子树
        FindPath(root->left, expectNumber - root->val);
        //遍历右子树
        FindPath(root->right, expectNumber - root->val);
        
        tmp.pop_back();
        return result;
    }
private:
    vector<vector<int> > result;
    vector<int> tmp;
};

9.二叉树的深度

题目描述:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
实现代码:
class Solution {
public:
    int TreeDepth(TreeNode* pRoot)
    {
        if(pRoot == NULL){
            return 0;
        }
        int left = TreeDepth(pRoot->left);
        int right = TreeDepth(pRoot->right);
        return (left > right) ? (left + 1) : (right + 1);
    }
};

10.判断是否为平行二叉树

题目描述:
平衡二叉树的定义是:所谓的平衡之意,就是树中任意一个结点下左右两个子树的高度差不超过 1。
实现代码:
class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot == NULL){
            return true;
        }
        int left = TreeDepth(pRoot->left);
        int right = TreeDepth(pRoot->right);
        int diff = left - right;
        if(diff > 1 || diff < -1){
            return false;
        }
        return IsBalanced_Solution(pRoot->right) && IsBalanced_Solution(pRoot->left);
    }
private:
    int TreeDepth(TreeNode* pRoot)
    {
        if(pRoot == NULL){
            return 0;
        }
        int left = TreeDepth(pRoot->left);
        int right = TreeDepth(pRoot->right);
        return (left > right) ? (left + 1) : (right + 1);
    }
};

11.二叉树的下一个节点

题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
实现代码:
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode == NULL){
            return NULL;
        }
        TreeLinkNode* pNext = NULL;
        // 当前结点有右子树,那么它的下一个结点就是它的右子树中最左子结点
        if(pNode->right != NULL){
            TreeLinkNode* pRight = pNode->right;
            while(pRight->left != NULL){
                pRight = pRight-> left;
            }
            pNext = pRight;
        }
        // 当前结点无右子树,则需要找到一个是它父结点的左子树结点的结点
        else if(pNode->next != NULL){
            // 当前结点
            TreeLinkNode* pCur = pNode;
            // 父节点
            TreeLinkNode* pPar = pNode->next;
            while(pPar != NULL && pCur == pPar->right){
                pCur = pPar;
                pPar = pCur->next;
            }
            pNext = pPar;
        }
        return pNext;
    }
};

12.对称二叉树

题目描述:
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
实现代码:
class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
        if(pRoot == NULL){
            return true;
        }
        return isSymmetriacalCor(pRoot, pRoot);
    }
private:
    bool isSymmetriacalCor(TreeNode* pRoot1, TreeNode* pRoot2){
        if(pRoot1 == NULL && pRoot2 == NULL){
            return true;
        }
        if(pRoot1 == NULL || pRoot2 == NULL){
            return false;
        }
        if(pRoot1->val != pRoot2->val){
            return false;
        }
        return isSymmetriacalCor(pRoot1->left, pRoot2->right) && isSymmetriacalCor(pRoot1->right, pRoot2->left);
    }
};

13.之字形打印二叉树

题目描述:
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
实现代码:
class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int> > result;
        if(pRoot == NULL){
            return result;
        }
        stack<TreeNode* > s[2];
        s[0].push(pRoot);
        while(!s[0].empty() || !s[1].empty()){
            vector<int> v[2];
            // 偶数行
            while(!s[0].empty()){
                v[0].push_back(s[0].top()->val);
                if(s[0].top()->left != NULL){
                    s[1].push(s[0].top()->left);
                }
                if(s[0].top()->right != NULL){
                    s[1].push(s[0].top()->right);
                }
                s[0].pop();
            }
            if(!v[0].empty()){
                result.push_back(v[0]);
            }
            // 奇数行
            while(!s[1].empty()){
                v[1].push_back(s[1].top()->val);
                if(s[1].top()->right != NULL){
                    s[0].push(s[1].top()->right);
                }
                if(s[1].top()->left != NULL){
                    s[0].push(s[1].top()->left);
                }
                s[1].pop();
            }
            if(!v[1].empty()){
                result.push_back(v[1]);
            }
        }
        return result;
    }
};

14.把二叉树打印成多行

题目描述:
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
实现代码:
class Solution {
public:
        vector<vector<int> > Print(TreeNode* pRoot) {
            vector<vector<int> > result;
            if(pRoot == NULL){
                return result;
            }
            queue<TreeNode* > nodes[2];
            nodes[0].push(pRoot);
            while(!nodes[0].empty() || !nodes[1].empty()){
                vector<int> v[2];
                while(!nodes[0].empty()){
                    v[0].push_back(nodes[0].front()->val);
                    if(nodes[0].front()->left != NULL){
                        nodes[1].push(nodes[0].front()->left);
                    }
                    if(nodes[0].front()->right != NULL){
                        nodes[1].push(nodes[0].front()->right);
                    }
                    nodes[0].pop();
                }
                if(!v[0].empty()){
                    result.push_back(v[0]);
                }
                while(!nodes[1].empty()){
                    v[1].push_back(nodes[1].front()->val);
                    if(nodes[1].front()->left != NULL){
                        nodes[0].push(nodes[1].front()->left);
                    }
                    if(nodes[1].front()->right != NULL){
                        nodes[0].push(nodes[1].front()->right);
                    }
                    nodes[1].pop();
                }
                if(!v[1].empty()){
                    result.push_back(v[1]);
                }
            }
            return result;
        }
};

15.序列化二叉树

题目描述:
请实现两个函数,分别用来序列化和反序列化二叉树
实现代码:
class Solution {
public:
    char* Serialize(TreeNode *root) {    
        if(!root){
            return NULL;
        }
        string str;
        SerializeCore(root, str);
        // 把str流中转换为字符串返回
        int length = str.length();
        char* res = new char[length+1];
        // 把str流中转换为字符串返回
        for(int i = 0; i < length; i++){
            res[i] = str[i];
        }
        res[length] = '\0';
        return res;
    }
    TreeNode* Deserialize(char *str) {
        if(!str){
            return NULL;
        }
        TreeNode* res = DeserializeCore(&str);
        return res;
    }
    void SerializeCore(TreeNode* root, string& str){
        // 如果指针为空,表示左子节点或右子节点为空,则在序列中用#表示
        if(!root){
            str += '#';
            return;
        }
        string tmp = to_string(root->val);
        str += tmp;
        // 加逗号,用于区分每个结点
        str += ',';
        SerializeCore(root->left, str);
        SerializeCore(root->right, str);
    }
    // 递归时改变了str值使其指向后面的序列,因此要声明为char**
    TreeNode* DeserializeCore(char** str){
        // 到达叶节点时,调用两次,都返回null,所以构建完毕,返回父节点的构建
        if(**str == '#'){
            (*str)++;
            return NULL;
        }
        // 因为整数是用字符串表示,一个字符表示一位,先进行转换
        int num = 0;
        while(**str != ',' && **str != '\0'){
            num = num * 10 + ((**str) - '0');
            (*str)++;
        }
        TreeNode* root = new TreeNode(num);
        if(**str == '\0'){
            return root;
        }
        else{
            (*str)++;
        }
        root->left = DeserializeCore(str);
        root->right = DeserializeCore(str);
        return root;
    }
};

16.二叉树的最小树深

题目描述:
 
给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最小深度  2.

实现代码:
class Solution {
public:
    int digui(TreeNode* root){
        if(root->left == NULL && root->right == NULL){
            return 1;
        }
        else if(root->left == NULL && root->right != NULL){
            return 1 + digui(root->right);
        }
        else if(root->left != NULL && root->right == NULL){
            return 1 + digui(root->left);
        }
        else{
            return 1 + min(digui(root->left),digui(root->right));
        }
    }
    int minDepth(TreeNode* root) {
        if(root == NULL){
            return 0;
        }
        else{
            return digui(root);
        }
    }
};

17.二叉树的最大树深

题目描述:
给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

实现代码:
class Solution {
public:
    int digui(TreeNode* root){
        if(root == NULL){
            return 0;
        }
        else{
            return 1 + max(digui(root->left),digui(root->right));
        }
    }
    int maxDepth(TreeNode* root) {
        int i = 0;
        if(root == NULL)
        {
            return 0;
        }
        else
        {   
            i = digui(root);
        }
        return i;
    }};

18.最长同值路径

题目描述:
给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。

注意:两个节点之间的路径长度由它们之间的边数表示。

示例 1:

输入:

              5
             / \
            4   5
           / \   \
          1   1   5

输出:

2

示例 2:

输入:

              1
             / \
            4   5
           / \   \
          4   4   5

输出:

2

注意: 给定的二叉树不超过10000个结点。 树的高度不超过1000。

实现代码:
class Solution {
public:
    int current_max=0;
    int longestUnivaluePath(TreeNode* root) {
        dfs(root);
        return current_max;
    }
    
    int dfs(TreeNode* root){
        if(root==NULL){
            return 0;
        }
        int left=dfs(root->left);
        int right=dfs(root->right);
        if(root->left!=NULL&&root->val==root->left->val){
            left+=1;
        }else{
            left=0;
        }
        if(root->right!=NULL&&root->val==root->right->val){
            right+=1;
        }else{
           right=0;
        }
       current_max=max(current_max,left+right);
        return max(left,right);
    }
};

19.二叉搜索树节点最小距离

题目描述:
给定一个二叉搜索树的根结点 root, 返回树中任意两节点的差的最小值。

示例:

输入: root = [4,2,6,1,3,null,null]
输出: 1
解释:
注意,root是树结点对象(TreeNode object),而不是数组。

给定的树 [4,2,6,1,3,null,null] 可表示为下图:

          4
        /   \
      2      6
     / \    
    1   3  

最小的差值是 1, 它是节点1和节点2的差值, 也是节点3和节点2的差值。

注意:

    二叉树的大小范围在 2 到 100。
    二叉树总是有效的,每个节点的值都是整数,且不重复。

实现代码:
class Solution {
public:
    void pre(vector<int> &res,TreeNode *root){
        if(root != NULL){
            pre(res,root->left);
            res.push_back(root->val);
            pre(res,root->right);
        }
    }
    int minDiffInBST(TreeNode* root) {
        vector<int> res;
        pre(res,root);
        vector<int> r;
        int min = 0;
        for(int i = 0;i < res.size() - 1;i++){
            r.push_back(res[i+1]-res[i]);
        }
        sort(r.begin(),r.end());
        return r[0];
    }
};

20.二叉搜索树的范围和

题目描述:
给定二叉搜索树的根结点 root,返回 L 和 R(含)之间的所有结点的值的和。

二叉搜索树保证具有唯一的值。

 

示例 1:

输入:root = [10,5,15,3,7,null,18], L = 7, R = 15
输出:32

示例 2:

输入:root = [10,5,15,3,7,13,18,1,null,6], L = 6, R = 10
输出:23

 

提示:

    树中的结点数量最多为 10000 个。
    最终的答案保证小于 2^31。

实现代码:
class Solution {
public:
    void pre(vector<int> &res,TreeNode * root){
        if(root != NULL){
            pre(res,root->left);
            res.push_back(root->val);
            pre(res,root->right);
        }
    }
    int rangeSumBST(TreeNode* root, int L, int R) {
        int value = 0;
        vector<int>res;
        pre(res,root);
        for(int i = 0;i < res.size();i++){
            if(res[i] >= L&&res[i] <= R)
            {
                value = value + res[i];
            }
        }
        return value;
    }
};

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

题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
实现代码:
class Solution {
public:
    bool VerifySquenceOfBST(vector<int> sequence) {
        return bst(sequence, 0, sequence.size() - 1);
    }
private:
    bool bst(vector<int> seq, int begin, int end){
        if(seq.empty() || begin > end){
            return false;
        }
        
        //根结点
        int root = seq[end];
        
        //在二叉搜索树中左子树的结点小于根结点
        int i = begin;
        for(; i < end; ++i){
            if(seq[i] > root){
                break;
            }
        }
        
        //在二叉搜索书中右子树的结点大于根结点
        for(int j = i; j < end; ++j){
            if(seq[j] < root){
                return false;
            }
        }
        
        //判断左子树是不是二叉搜索树
        bool left = true;
        if(i > begin){
            left = bst(seq, begin, i - 1);
        }
        
        //判断右子树是不是二叉搜索树
        bool right = true;
        if(i < end - 1){
            right = bst(seq, i , end - 1);
        }
        
        return left && right;
    }
};

22.二叉搜索树第k个节点

题目描述:

给定一颗二叉搜索树,请找出其中的第k大的结点。例如,在下图中,按结点数值大小顺序第三个结点的值为4。

剑指Offer(六十二):二叉搜索树的第k个结点

这棵树是二叉搜索树,首先想到的是二叉搜索树的一个特点:左子结点的值 < 根结点的值 < 右子结点的值。

实现代码:
class Solution {
public:
    TreeNode* KthNode(TreeNode* pRoot, int k)
    {
        if(pRoot == NULL || k == 0){
            return NULL;
        }
        return KthNodeCore(pRoot, k);
    }
private:
    TreeNode* KthNodeCore(TreeNode* pRoot, int &k){
        TreeNode* target = NULL;
        // 先遍历左结点
        if(pRoot->left != NULL){
            target = KthNodeCore(pRoot->left, k);
        }
        // 如果没有找到target,则继续减小k,如果k等于1,说明到了第k大的数
        if(target == NULL){
            if(k == 1){
                target = pRoot;
            }
            k--;
        }
        // 如果没有找到target,继续找右结点
        if(pRoot->right != NULL && target == NULL){
            target = KthNodeCore(pRoot->right, k);
        }
        return target;
    }
};
 
 
posted @ 2019-08-20 21:30  小菜鸡的刨坑路  阅读(565)  评论(0编辑  收藏  举报