算法练习-二叉树

一、二叉树前序遍历


  struct TreeNode {
 	int val;
 	struct TreeNode *left;
 	struct TreeNode *right;
 	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
  };
 

前序遍历表示先 遍历 root->left->right

class Solution {
public:
    vector preorderTraversal(TreeNode* root) {
        vector res;
        if(root == NULL) return res; 
        printPreTree(res,root);
        return res;       
    }
    void printPreTree(vector& vec,TreeNode* node) {
        if(node == NULL) return;
        vec.push_back(node->val); // 先访问根节点
        printPreTree(vec,node->left); // 访问左边节点
        printPreTree(vec,node->right); //访问右边节点
    }
};

二、二叉树前序遍历

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

三、二叉树最大深度

求给定二叉树的最大深度,深度是指树的根节点到任一叶子节点路径上节点的数量。最大深度是所有叶子节点的深度的最大值

解法一,使用递归计算

1.计算左边node 的深度,计算右边node的深度,最终max(left,right)

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

class Solution {
public:
    /**
     * 
     * @param root TreeNode类 
     * @return int整型
     */
    int maxDepth(TreeNode* root) {
       //递归计算
       if(root == NULL) return 0;
       int maxLen = max(maxDepth(root->left),maxDepth(root->right)) + 1;
       return maxLen;
    }
};

解法二,使用队列进行计算

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

#include 
class Solution {
public:
    /**
     * 
     * @param root TreeNode类 
     * @return int整型
     */
    int maxDepth(TreeNode* root) {
      if(root == NULL) return 0;
      queue q;
      q.push(root);
      int res = 0;
      while (!q.empty()) {
        int size = q.size();
        res += 1;
        for(int i = 0; i < size; i++) {
            TreeNode* node = q.front();
            if(node->left) q.push(node->left);
            if(node->right) q.push(node->right);
            q.pop(); //出队列
        }
      }
      return res;
    }
};

 四、二叉树的层次遍历

        给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历)
例如:给定的二叉树是{3,9,20,#,#,15,7}

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

class Solution {
public:
    vector > levelOrder(TreeNode* root) {
        vector> res;
        if(root == NULL) return res;
        queue q;
        q.push(root);
        while(!q.empty()) {
            vector vec;
            int size = q.size();
            for(int i = 0; i < size; i++) {
                TreeNode* node = q.front();
                if(node->left) q.push(node->left);
                if(node->right) q.push(node->right);
                vec.push_back(node->val);
                q.pop();
            }
            res.push_back(vec);
        }
        return res;   
    }
};

   五、二叉树中和为某一值的路径(一)

        给定一个二叉树root和一个值 sum ,判断是否有从根节点到叶子节点的节点值之和等于 sum 的路径

        1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点

        2.叶子节点是指没有子节点的节点

        3.路径只能从父节点到子节点,不能从子节点到父节点

        4.总节点数目为n

方案一:

递归解决方案

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

class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if(root == NULL) return false;
        return traversal(root,sum - root->val);
    }
    bool traversal(TreeNode* cur,int count) {
        //  题目中限制的是叶子结点信息,递归的终止条件. count = 0 表示的是减去当前数值得到的结果
        if(cur->left == NULL && cur->right == NULL && count == 0) return true;
        if(cur->left == NULL && cur->right == NULL) return false; //叶子结点的同时没找到结果
        if(cur->left) {
            count = count - cur->left->val;
            if(traversal(cur->left,count)) return true;
            //回溯操作
            count += cur->left->val;
        }

        if(cur->right) {
            count = count - cur->right->val;
            if(traversal(cur->right, count)) return true;
            count += cur->right->val;
        }
        return false;
    }
};

方案二:

遍历迭代方案

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

#include 
class Solution {
  public:
    bool hasPathSum(TreeNode* root, int sum) {
        if (root == NULL) return false;
        stack> st;
        st.push(make_pair(root, root->val));
        while (!st.empty()) {
            pair node = st.top(); //获取stack顶部元素
            st.pop();
            if (node.first->left == NULL && node.first->right == NULL &&
                    sum == node.second) {
                return true;
            }
            if (node.first->left) {
                st.push(make_pair(node.first->left, node.second + node.first->left->val));
            }
            if (node.first->right) {
                st.push(make_pair(node.first->right, node.second + node.first->right->val));
            }
        }
        return false;
    }
};

 六、对称的二叉树

        给定一棵二叉树,判断其是否是自身的镜像(即:是否对称)


/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot) {
       if(pRoot == NULL) return true;
       return isSame(pRoot->left,pRoot->right);
    }
    bool isSame(TreeNode* left,TreeNode* right) {
        if(left == NULL && right == NULL) return true;
        if(left == NULL || right == NULL ) return false;
        if(left->val != right->val) return false; //left 不等于 right
        //需要判断left 的left ?= right 的 right
        return isSame(left->left,right->right) && isSame(left->right, right->left);

    }

};

需要注意的是,第三层的时候,left的左边结点需要和 right的right结点相等,并且left的right 的结点和right的left的结点一样

七、判断是不是平衡二叉树

        输入一棵节点数为 n 二叉树,判断该二叉树是否是平衡二叉树。

        在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

        平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树

class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot == NULL) return true;
        int depth = abs(getDepth(pRoot->left) - getDepth(pRoot->right));
        if (depth > 1) return false;
        return IsBalanced_Solution(pRoot->left) && IsBalanced_Solution(pRoot->right);
    }

    int getDepth(TreeNode* node) {
        if (node == NULL) return 0;
        return max(getDepth(node->left),getDepth(node->right)) + 1;
    }

};

    第一步首先是获取结点的高度,然后再去判断左边结点和右边结点的高度绝对值差

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

        给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

        1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q,最近公共祖先LCA(T,p,q)表示一个节点x,满足x是p和q的祖先且x的深度尽可能大。在这里,一个节点也可以是它自己的祖先.

        2.二叉搜索树是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值

        3.所有节点的值都是唯一的。

        4.p、q 为不同节点且均存在于给定的二叉搜索树中

     方案一(递归方案):

        

/**
 * struct TreeNode {
 *  int val;
 *  struct TreeNode *left;
 *  struct TreeNode *right;
 *  TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
  public:
    int lowestCommonAncestor(TreeNode* root, int p, int q) {
        //注意二叉搜索树的特性
        if(root == NULL) return -1;
        if(root->val > p && root->val > q) { //说明公共祖先在左边子树中
            return lowestCommonAncestor(root->left,p,q);
        }
        else if (root->val < p && root->val < q) {
            return lowestCommonAncestor(root->right,p,q);
        }
        else { // p 或者q 在root的左右边
            return root->val;
        }
        return -1;
    }
};

方案二:(迭代方案)

/**
 * struct TreeNode {
 *  int val;
 *  struct TreeNode *left;
 *  struct TreeNode *right;
 *  TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
  public:
    int lowestCommonAncestor(TreeNode* root, int p, int q) {
        //注意二叉搜索树的特性
        if(root == NULL) return -1;
        while(root) {
            if(root->val < p && root->val < q) {
                root = root->right;
            }
            else if(root->val > q && root ->val > p) {
                root = root ->left;
            }
            else {
                return root->val;
            }
        }
        return -1;
    }
};

最主要的是记住二叉搜索树的特性,根结点大于左结点,且根结点小于右边结点大小,需要注意的是同时大于q和p ,还是同时小于p和q

九、合并两颗二叉树

        已知两颗二叉树,将它们合并成一颗二叉树。合并规则是:都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替

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

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if(t1 == NULL && t2 == NULL) return NULL;
        if(t1 == NULL) return t2;
        if(t2 == NULL) return t1;
        if(t1 && t2) {
            t1->val +=  t2->val;
        }
        t1->left = mergeTrees(t1->left,t2->left);
        t1->right = mergeTrees(t1->right, t2->right);
        return t1;
    }
};

十、二叉树的最近公共祖先

        给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点

        

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

class Solution {
public:
    int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
        if(root == NULL) return -1;
        TreeNode * node = help(root,o1,o2);
        return node->val;
    }

    TreeNode* help(TreeNode* root,int p,int q) {
        if(root == NULL) return NULL;
        if(root->val == p || root->val == q) return root; //递归的终止条件返回当前数值
        TreeNode* left = help(root->left,p,q);
        TreeNode* right = help(root->right,p,q);

        if(left == NULL) return right;
        if(right == NULL) return left;
        if(left != NULL && right != NULL) return root;
        return NULL;
    }
};

你可能感兴趣的:(算法练习,算法,数据结构,c++)