二叉树 + 递归 + 分治法总结

Posted bella2017

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树 + 递归 + 分治法总结相关的知识,希望对你有一定的参考价值。

二叉树递归相关题目的时间复杂度基本上都是O(n) = 一共有n个点 + 每个点的时间复杂度(1)

而二叉树分治法最坏的时间复杂度为O(n^2)

 

时间复杂度:T(n) = 2T(n/2) + O(1) = O(n)

Merge Sort, Quick Sort: T(n) = 2T(n/2) + O(n) = O(nlogn)

技术图片

 

前序遍历:

 技术图片

 

解法一:递归,通常是设置一个全局变量来保存结果。

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> preorderTraversal(TreeNode* root) 
        vector<int> result;
        traverse(root, result);
        return result;
    
    void traverse(TreeNode* root, vector<int>& res)
        //递归终止条件
        if(root == NULL)
            return;
        res.push_back(root->val);
        traverse(root->left, res);
        traverse(root->right, res);
    
;

解法二:Divide & Conquer

 技术图片

 

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> preorderTraversal(TreeNode* root) 
        vector<int> res;
        if(root == NULL)
            return res;
        
        //divide
        vector<int> left = preorderTraversal(root->left);
        vector<int> right = preorderTraversal(root->right);
        
        //conquer
        res.push_back(root->val);
        for(auto i : left)
            res.push_back(i);
        for(auto i : right)
            res.push_back(i);
        return res;
    
;

 解法三:非递归版本C++

采用堆栈实现。

  1. 根节点先入栈
  2. 判断栈是否为空,飞空则出栈并加入结果队列
  3. 先把右子树入栈再把左子树入栈,这样出栈的时候是先左后右,(中间根已经在上一步输出)
/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> preorderTraversal(TreeNode* root) 
        vector<int> res;
        if(root == NULL)
            return res;
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty())
            TreeNode* node = st.top();
            st.pop();
            res.push_back(node->val);
            if(node->right)
                st.push(node->right);
            if(node->left)
                st.push(node->left);
        
        return res;
    
;

 

中序遍历:

技术图片

 一. 递归

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> preorderTraversal(TreeNode* root) 
        vector<int> res;
        if(root == NULL)
            return res;
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty())
            TreeNode* node = st.top();
            st.pop();
            res.push_back(node->val);
            if(node->right)
                st.push(node->right);
            if(node->left)
                st.push(node->left);
        
        return res;
    
;

二. Divide and Quaqer

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> inorderTraversal(TreeNode* root) 
        vector<int> res;
        if(root == NULL)
            return res;
        
        vector<int> left = inorderTraversal(root->left);
        vector<int> right = inorderTraversal(root->right);
        
        for(int i : left)
            res.push_back(i);
        res.push_back(root->val);
        for(int i: right)
            res.push_back(i);
        
        return res;
    
;

三. 非递归,用栈来实现。

栈或者当前结点不为空时:

1)把当前结点压入栈中,然后继续压入它的左结点,直到左结点为空;

2)将栈顶元素的值保存在res中,并弹出;

3)转到右结点。

 

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> inorderTraversal(TreeNode* root) 
        vector<int> res;
        stack<TreeNode* > st;
        TreeNode* cur = root;
        while(cur || !st.empty())
            while(cur)
                st.push(cur);
                cur = cur->left;
            
            cur = st.top();
            st.pop();
            res.push_back(cur->val);
            cur = cur->right;
        
        return res;
    
;

 

后序遍历:

技术图片

一.

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> postorderTraversal(TreeNode* root) 
        vector<int> res;
        traverse(root, res);
        return res;
    
    void traverse(TreeNode* root, vector<int>& res)
        if(root == NULL)
            return;
        traverse(root->left, res);
        traverse(root->right, res);
        res.push_back(root->val);
    
;

 

二.

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> postorderTraversal(TreeNode* root) 
        vector<int> res;
        if(root == NULL)
            return res;
       
        vector<int> left = postorderTraversal(root->left);
        vector<int> right = postorderTraversal(root->right);
        
        for(int i: left)
            res.push_back(i);
        for(int i: right)
            res.push_back(i);
        res.push_back(root->val);
        
        return res;
    
;

 

三.

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<int> postorderTraversal(TreeNode* root) 
        vector<int> res;
        stack<TreeNode* > st;
        if(root == NULL)
            return res;
        st.push(root);
        while(!st.empty())
            TreeNode* tmp = st.top();
            st.pop();
            res.insert(res.begin(), tmp->val);   //在前端插入
            if(tmp->left)
                st.push(tmp->left);
            if(tmp->right)
                st.push(tmp->right);
        
        return res;
    
;

 

技术图片

 

 一.

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
private:
    int dep_max;    //全局变量
public:
    int maxDepth(TreeNode* root) 
        dep_max = 0;
        helper(root, 1);  //1为当前根结点
        return dep_max;  
         
    
    void helper(TreeNode* root, int depth)
        if(root==NULL) return;
        
        dep_max = max(dep_max, depth);
        helper(root->left, depth+1);
        helper(root->right, depth+1);
    
;

二.

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    int maxDepth(TreeNode* root) 
        if(root==NULL) return 0;
        
        //左右子树的深度
        int left = maxDepth(root->left);
        int right = maxDepth(root->right);

        return max(left, right)+1;  
         
    

    
;

平衡二叉树:左右子树高度相差不超过1

技术图片

 

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    bool isBalanced(TreeNode* root) 
        if(root==NULL)
            return true;
        if(abs(getDepth(root->left) - getDepth(root->right)) > 1)
            return false;
        return isBalanced(root->left) && isBalanced(root->right);
    
    int getDepth(TreeNode* root)
        if(!root)
            return 0;
        return max(getDepth(root->left), getDepth(root->right)) + 1;
    
    
;

上面的方法使得每个结点都会被上面的点计算深度时访问一次,优化一下:若发现某个结点的子树不平衡,则不计算它的深度,直接返回-1

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    bool isBalanced(TreeNode* root) 
        if(depth(root) == -1)
            return false;
        return true;
    
    int depth(TreeNode* root)
        if(!root)
            return 0;
        int left = depth(root->left);
        if(left==-1)
            return -1;
        int right = depth(root->right);
        if(right == -1)
            return -1;
        int dif = abs(left - right);
        if(dif>1)
            return -1;
        else
            return max(left, right)+1;
    
;

 

技术图片

二叉搜索树的性质是:左子树的值 < 根节点 < 右子树的值

 

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)         
        if(p->val > q->val)
            swap(p,q);   // ensure p < q
        
        while(root)
            if(root->val < p->val)
                root = root->right;
            else if(root->val > q->val)
                root = root->left;
            else
                return root;
        
        return NULL;
    
;

 

已知A和B的父亲结点:

 技术图片

技术图片

技术图片

思路:把A和A的父结点保存在set中,若在B及B的父结点中找到一个和set中相同的结点,就返回这个公共祖先。

 

/**
 * Definition of ParentTreeNode:
 * class ParentTreeNode 
 * public:
 *     int val;
 *     ParentTreeNode *parent, *left, *right;
 * 
 */


class Solution 
public:
    /*
     * @param root: The root of the tree
     * @param A: node in the tree
     * @param B: node in the tree
     * @return: The lowest common ancestor of A and B
     */
    ParentTreeNode * lowestCommonAncestorII(ParentTreeNode * root, ParentTreeNode * A, ParentTreeNode * B) 
        // write your code here
        if(root == NULL)
            return NULL;
            
        unordered_set<ParentTreeNode*> s;  //保存A向上的路径
        while(A!=NULL)
            s.insert(A);
            A = A->parent;
        
        
        while(B)
            if(s.find(B) == s.end())
                //s中找不到相同的结点
                B = B->parent;
            else
                return B;
        
        
    
;

 

未知p,q的父亲结点:

技术图片

分治法:

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
//若找到了LCA,就返回LCA,即 p和q出现在一左一右,返回它的根结点
//若只找到n1, 就返回n1
//若只找到了n2, 就返回n2
//若都不存在,返回NULL
class Solution 
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
        if(root == NULL)
            return NULL;
        if(root == p || root == q)
            return root;
        
        //divide
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        
        //Conquer
        if(left != NULL && right != NULL)
            return root;
        
        if(left != NULL)
            return left;
        
        if(right != NULL)
            return right;
        
        return NULL;
    
;

 

 

/**
 * Definition of TreeNode:
 * class TreeNode 
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) 
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     
 * 
 */
//一颗二叉树,求从根结点到叶子结点的路径的最大值;求从根结点到任一结点的路径的最大值
class Solution 
public:
    /**
     * @param root: The root of binary tree.
     * @return: An integer
     */
    int maxPathSum(TreeNode * root) 
        // write your code here
        if (root == NULL)
            return 0;
        int left = maxPathSum(root->left);
        int right = maxPathSum(root->right);

        //root -> leaf
        //return max(left, right) + root->val;

        //root-> anynode
        return max(0, max(left, right)) + root->val;
    
;

 

从任一结点到任一结点路径的最大值:

技术图片

 

参考链接:https://www.geeksforgeeks.org/find-maximum-path-sum-in-a-binary-tree/

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
//any to any node: 最长路径的位置:完全在左边;完全在右边;跨过根结点
 //O(n)
class Solution 
public:
    int findMax(TreeNode* root, int &res)
        if(root == NULL)
            return 0;
        
        int l = findMax(root->left, res);
        int r = findMax(root->right, res);
        
        int max_single = max(max(l, r)+root->val, root->val);
        int max_round = max(max_single, l+r+root->val);
        
        res = max(res, max_round);   //store the maximum result
        return max_single;
    
    
    int maxPathSum(TreeNode* root) 
        int res = INT_MIN;
        findMax(root, res);
        return res;
    
;

 

 技术图片

 

/**
 * Definition for a binary tree node.
 * struct TreeNode 
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) 
 * ;
 */
class Solution 
public:
    vector<string> binaryTreePaths(TreeNode* root) 
        vector<string> res;
        if(root == NULL)
            return res;   //返回空vector res
        
        if(root->left==NULL && root->right==NULL)
            res.push_back(to_string(root->val));
        
        //divide
        vector<string> left = binaryTreePaths(root->left);
        vector<string> right = binaryTreePaths(root->right);
        
        //conquer
        for(string s : left)
            res.push_back(to_string(root->val) + "->" + s);
        for(string s : right)
            res.push_back(to_string(root->val) + "->" + s);
        
        return res;
        
    
;

 

以上是关于二叉树 + 递归 + 分治法总结的主要内容,如果未能解决你的问题,请参考以下文章

二叉树与分治法算法

二叉树算法小结

二叉树算法总结

二叉树 - 20190205

Leetcode之分治法专题-654. 最大二叉树(Maximum Binary Tree)

(二叉树)原来Java 求解二叉树的最大深度如此简单 !!!