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

二叉树递归相关题目的时间复杂度基本上都是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;

    }
};

原文地址:https://www.cnblogs.com/Bella2017/p/11384471.html

时间: 2024-10-10 17:09:19

二叉树 + 递归 + 分治法总结的相关文章

第三节.二叉树和分治法

tips: 1.掌握用栈来实现非递归法的前序遍历和中序遍历. 2.区分递归和分治.分治是一种算法,递归是程序的一种实现方式.递归不一定有分治的思想,例如在二叉树遍历中,遍历法也是用递归实现的,但它不是分治法.90%的二叉树题目考虑用分治法. 3求层序遍历的题目要用BFS.掌握用一个队列来做二叉树的层序遍历. 4了解一下用DFS来做层序遍历.

分治法与递归编程步骤

分治法是一种很强大的算法设计方法.基本思想是:将原问题分解为几个规模小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 在分治策略中,递归地求解一个问题,在每层递归中应用如下三个步骤: (1)分解(Divide):将原问题分解为一些子问题,子问题的形式与原问题一样,只是规模更小. (2)解决(Conquer):递归地解出子问题.如果子问题规模足够小,则停止递归,直接求解. (3)合并(Combine):将子问题的解组合成原问题的解. 分治思想体现在编码上,

动态规划和分治法,贪心算法以及递归的再一次深刻理解和体会

每次体会算法都有新的感觉,刷题越多,对算法的理解感觉也就越深刻. 下面我们来重新体会下分治法,动态规划,贪心法,递归的理解. 1.分治法: 将问题分成单独的阶段,每个阶段互相不干扰很独立,如10米长的木棍,切成10段,每段去解决每一段的问题.(阶段没有关系) 2.贪心法 站在全局的角度,也是将问题堪称分为多个阶段,只不过阶段和阶段之间有一定的递进关系,如从5毛,1元,2毛,1毛,2元中,去找最少的钱币构成10块钱.首先是站在全局的角度,先从中取其最大值,为第一阶段,然后在从剩余的当中在找最大值,

递归与分治法

分治法思想 把问题分解为k个规模较小的子问题,这些子问题(互相独立且)结构与原来问题的结构相同,再递归地求解这些子问题. 问题分解成子问题:(divide) 当达到某个阈值n0时,给出直接求解的方法:(conquer) 最后把各个子问题的解合并起来,得到原来问题的解:(merge) 算法设计伪代码 时间复杂性 分析分治法的运行时间,先列出递归方程,例如 典型例子 mergesort等 原文地址:https://www.cnblogs.com/eniac1946/p/8733531.html

分治法(一)

这篇文章将讨论: 1) 分治策略的思想和理论 2) 几个分治策略的例子:合并排序,快速排序,折半查找,二叉遍历树及其相关特性. 说明:这几个例子在前面都写过了,这里又拿出来,从算法设计的策略的角度把它们放在一起来比较,看看分治是如何实现滴.由于内容太多,我将再花一篇文章来写4个之前没有写过的分治算法:1,大整数乘法   2,矩阵乘法的分治策略   3,最近点对  4,凸包问题,请见下一篇. 好了,切入正题. --------------------------------------------

leetcode 23. Merge k Sorted Lists(堆||分治法)

Merge k sorted linked lists and return it as one sorted list. 题意:把k个已经排好序的链表整合到一个链表中,并且这个链表是排了序的. 题解:这是一道经典好题,值得仔细一说. 有两种方法,假设每个链表的平均长度是n,那么这两种方法的时间复杂度都是O(nklogk). 方法一: 基本思路是:把k个链表开头的值排个序,每次取最小的一个值放到答案链表中,这次取完之后更新这个值为它后面的一个值.接着这么取一直到全部取完.那么每次更新之后怎么对当

专题:分治法

分治法(Divide and Conquer) 作为五大算法之一的分治法,可算是最早接触的一种算法.分治法,与其说是一种算法,不如将其称为策略来的更贴切一些.算法的思想就是将大问题分成小问题,并解决小问题之后合并起来生成大问题的解. 分治法的精髓: 分--将问题分解为规模更小的子问题: 治--将这些规模更小的子问题逐个击破: 合--将已解决的子问题合并,最终得出“母”问题的解: 分治法的作用,自然是让程序更加快速地处理问题.比如一个n的问题分解成两个n/2的问题,并由两个人来完成,效率就会快一些

分治法

分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同.递归的解这些子问题,然后将各子问题的解合并得到原问题的解. 分治法所能解决的问题一般具有以下几个特征: 1) 该问题的规模缩小到一定的程度就可以容易地解决 2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质. 3) 利用该问题分解出的子问题的解可以合并为该问题的解: 4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题. 分治法的基本步骤:分治法在

算法实验:分治法合并排序(C++)

这篇文章分两部分来写,第一部分写代码的实现过程,第二部分把实验报告从头到尾呈现出来. 我习惯调试使用的编译器是DEV C++,不是vs系列的,可能头文件上有点区别.但是下面的报告是我放到vs里面测试过的,可以直接用,不影响. 第一部分:(解析) 题目:随机产生一个整型数组,然后用合并排序将该数组做升序排列,要求输出排序前和排序后的数组. 题目分析: 需要随机产生一个整数数组: 采用的算法是合并排序,也就是用归并排序: 输出排序后的数组. 随机产生一个整数数组:这个问题首先想到的是用rand()函