力扣二叉树专题Ⅰ

在这里插入图片描述

二叉树基础理论

满二叉树

只有度数为零和度数为二的结点,且度数为零的结点在同一层上。
深度为k,有2^k-1个结点的二叉树

完全二叉树

从满二叉树而来,从右下角水平向左去掉结点而形成的树。
若最底层为第h层,则该层包含[1, 2^(h-1)]个结点。

用完全二叉树实现优先队列(堆排序)——
把优先值最大的元素(根结点)出列,可分为如下步骤:
1.交换首尾两个元素的位置,这样尾元素将会成为根结点,堆有序被打破;
2.剪掉被交换到末尾的原根元素;
3.把交换到根结点的元素下沉到合适位置,重新调整为大顶堆;
4.返回被剪出的元素,即为需要出列的最大优先值元素。

二叉搜索树

若左子树不空,左子树上所有结点值均小于根结点值;
若右子树不空,右子树上所有结点值均大于根结点值。

平衡二叉搜索树(AVL)

带了平衡功能的二叉搜索树
平衡功能:是空树或者左右两子树的高度差绝对值不超过1

map、set、multimap、multiset底层都是AVL

二叉树的遍历方式

在这里插入图片描述

前序遍历(递归法)

LC 第144题

耳熟能详的做法:

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

前序遍历(迭代法)

递归能做的,栈也能做!

不用递归,使用栈,这样的话,就需要自己考虑逻辑。为什么是先压右结点呢,因为左结点在上,才可以先pop出来啊。

class Solution {
public:
    vector<int> preorderTraversal(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.push_back(tmp->val);
            if(tmp->right) st.push(tmp->right);
            if(tmp->left) st.push(tmp->left);
        }
        return res;
    }
};

中序遍历(迭代法)

递归法就不贴了哈(换一换顺序的事)

LC 第94题

发现中序遍历(迭代)不是把前序遍历(迭代)稍微改下就行得通的了,因为前序要处理的元素(放入结果数组中)和要访问的元素是一样的(都是根结点),但这次不同,中序要处理的元素在最底部,而要访问的元素是一层层的往下,处理顺序和访问顺序不同。需要借助指针

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

后序遍历(迭代法)

LC 第145题

既然是“左右中”,那么就是“中右左”反过来,我们在前序遍历时是“中左右”,那么只需要将左右结点的入栈顺序换一下就好啦

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

二叉树的层序遍历

LC 第102题

注意每次队列里进的都是新一层的结点。

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

二叉树的层次遍历Ⅱ

LC 第107题

就是把上一题的容器翻转一下啦。

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        queue<TreeNode*> q;
        if(root != NULL) q.push(root);
        vector<vector<int>> res;
        while(!q.empty()){
            int s = q.size();
            vector<int> v;
            for(int i = 0; i < s; i++){
                TreeNode* cur = q.front();
                v.push_back(cur->val);
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);
                q.pop();
            }
            res.push_back(v);
        }
        reverse(res.begin(), res.end());
        return res;
    }
};

二叉树的右视图

LC 第199题

直接取每一层的最右元素啦

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

二叉树的层平均值

LC 第637题

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

N叉树的层序遍历

LC 第429题

遍历vector就是遍历数组呀~

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        queue<Node*> q;
        if(root != NULL) q.push(root);
        vector<vector<int>> res;
        while(!q.empty()){
            int s = q.size();
            vector<int> v;
            for(int i = 0; i < s; i++){
                Node* cur = q.front();
                v.push_back(cur->val);
                for(int j = 0; j < cur->children.size(); j++){
                    q.push(cur->children[j]);
                }
                q.pop();
            }
            res.push_back(v);
        }
        return res;
    }
};

在每个树行中找最大值

LC 第515题

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

填充每个结点的下一个右侧结点指针(Ⅰ和Ⅱ同解)

LC 第116题
LC 第117题

class Solution {
public:
    Node* connect(Node* root) {
        queue<Node*> q;
        if(root != NULL) q.push(root);
        while(!q.empty()){
            int s = q.size();
            for(int i = 0; i < s; i++){
                Node* cur = q.front();
                q.pop();
                if(i == s-1) cur->next = NULL;
                else cur->next = q.front();
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);   
            }
        }
        return root;
    }
};

以上的八个题目全部都是在层序遍历的基础上稍微修改就可以AC的!太快乐了⑧!
所以说,这些模板题全是层序遍历的子题(还是归到遍历方式这个大的主题下面)

二叉树属性

对称二叉树

LC 第101题

比较的是两棵子树的内侧结点和外侧结点。

递归法
class Solution {
public:
    bool Compare(TreeNode* left, TreeNode* right){
        if(!left && !right) return true;
        else if((!left&&right) || (left&&!right)) return false;
        else if(left->val != right->val) return false;
        bool outside = Compare(left->left, right->right);
        bool inside = Compare(left->right, right->left);
        return outside && inside;
    }
    bool isSymmetric(TreeNode* root) {
        if(root == NULL) return true;
        return Compare(root->left, root->right);
    }
};
迭代法

用栈/队列均可,队列只需要把stack改为queue

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(root == NULL) return true;
        stack<TreeNode*> st;
        st.push(root->right);
        st.push(root->left);
        while(!st.empty()){
            TreeNode* left = st.top(); st.pop();
            TreeNode* right = st.top(); st.pop();
            if(!left && !right) continue; //左右皆空,继续
            if(!left || !right || left->val!=right->val) return false;
            st.push(left->right);
            st.push(right->left);
            st.push(right->right);
            st.push(left->left);
        }
        return true;
    }
};

相同的树

LC 第100题

递归法
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(!p && !q) return true;
        else if(!q || !p || p->val != q->val) return false;
        else return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    }
};
迭代法
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(!p && !q) return true;
        queue<TreeNode*> que;
        que.push(p); que.push(q);
        while(!que.empty()){
            TreeNode* right = que.front(); que.pop();
            TreeNode* left = que.front(); que.pop();
            if(!right && !left) continue;
            if(!right || !left || right->val!=left->val) return false;
            que.push(left->left);
            que.push(right->left);
            que.push(left->right);
            que.push(right->right);
        }
        return true;
    }
};

二叉树最大深度

LC 第104题

递归法
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root ==  NULL) return 0;
        if(!root->left && !root->right) return 1;
        else return max(maxDepth(root->left), maxDepth(root->right)) + 1;
    }
};
迭代法(用队列更方便)
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root == NULL) return 0;
        queue<TreeNode*> q;
        int depth = 0;
        q.push(root);
        while(!q.empty()){
            int s = q.size();
            for(int i = 0; i < s; i++){
                TreeNode* cur =q.front();
                q.pop();
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);
            }
            depth++;
        }
        return depth;
    }
};

N叉树的最大深度

LC 第559题

递归法
class Solution {
public:
    int maxDepth(Node* root) {
       if(root == NULL) return 0;
        int depth = 0;
        for(int i = 0; i < root->children.size(); i++){
            depth = max(depth, maxDepth(root->children[i]));
        }
        return depth+1;
    }
};
迭代法
class Solution {
public:
    int maxDepth(Node* root) {
        if(root == NULL) return 0;
        queue<Node*> q;
        int depth = 0;
        q.push(root);
        while(!q.empty()){
            int s = q.size();
            for(int i = 0; i < s; i++){
                Node* cur =q.front();
                q.pop();
                for(int j = 0; j < cur->children.size(); j++){
                    q.push(cur->children[j]);
                }
            }
            depth++;
        }
        return depth;
    }
};

二叉树最小深度

LC 第111题

一排一排的找结点,当发现某个结点没有左右孩子的时候就返回深度。

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root == NULL) return 0;
        queue<TreeNode*> q;
        int depth = 0;
        q.push(root);
        while(!q.empty()){
            depth++;
            int s = q.size();
            for(int i = 0; i < s; i++){
                TreeNode* cur = q.front();
                q.pop();
                if(!cur->left && !cur->right) return depth;
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);
            }
        }
        return depth;
    }
};

完全二叉树的节点个数

LC 第222题

递归法
class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root) return 0;
        if(!root->left && !root->right) return 1;
        return countNodes(root->left) + countNodes(root->right) + 1; //别忘了加上根结点的一个
    }
};
迭代法

res每次都加一层的结点数(对每次入队入一层的理解更深了呢)

class Solution {
public:
    int countNodes(TreeNode* root) {
        queue<TreeNode*> q;
        if(!root) return 0;
        else q.push(root);
        int res = 0;
        while(!q.empty()){
            int s = q.size(); //队列长度要提前确定,因为在变
            res += s;
            for(int i = 0; i < s; i++){
                TreeNode* tmp = q.front(); //在这里取队头(用这层的结点入下一层的结点)
                q.pop();
                if(tmp->left) q.push(tmp->left);
                if(tmp->right) q.push(tmp->right);
            }
        }
        return res;
    }
};
完全二叉树的特性

对于完全二叉树只有两种情况:
① 满二叉树
② 问左右孩子,一旦为满二叉树就按①算(单个结点算满二叉树)

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root) return 0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int leftDepth = 0, rightDepth = 0;
        while(left){
            leftDepth++;
            left = left->left;
        }
        while(right){
            rightDepth++;
            right = right->right;
        }
        if(leftDepth == rightDepth) return (2<<leftDepth) - 1;
        return countNodes(root->left) + countNodes(root->right)+ 1;
    }
};

平衡二叉树

LC 第110题

给定一个二叉树,判断它是否是高度平衡的二叉树。

求最大深度的方法好像在此已经不再适用。

深度:从根结点到该结点的最长简单路径边的条数;(从上到下——中左右)
高度:从该结点到叶子结点的最长简单路径边的条数。(从下到上——左右中)

class Solution {
public:  
    int getHeight(TreeNode* node){
        if(!node) return 0;
        int leftHeight = getHeight(node->left);
        if(leftHeight == -1) return -1;
        int rightHeight = getHeight(node->right);
        if(rightHeight == -1) return -1;
        return abs(leftHeight - rightHeight) > 1 ? -1 : max(leftHeight, rightHeight) + 1;
    }
    bool isBalanced(TreeNode* root) {
        return getHeight(root) == -1 ? false : true;
    }
};

二叉树的所有路径

LC 第257题

递归法(回溯)

递归和回溯不分家

class Solution {
public:
    void findPath(TreeNode* cur, vector<int>& path, vector<string>& res){
        path.push_back(cur->val);
        if(!cur->left && !cur->right){
            string thisPath;
            for(int i = 0; i < path.size()-1; i++){
                thisPath += to_string(path[i]);
                thisPath += "->";
            }
            thisPath += to_string(path[path.size()-1]);
            res.push_back(thisPath);
            return;
        }
        if(cur->left){
            findPath(cur->left, path, res);
            path.pop_back();
        }
        if(cur->right){
            findPath(cur->right, path, res);
            path.pop_back();
        }
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> res;
        vector<int> path;
        findPath(root, path, res);
        return res;
    }
};
递归法(隐藏的回溯)
class Solution {
public:
    void TravelPath(TreeNode* cur, string path, vector<string>& res){
        path += to_string(cur->val);
        if(!cur->left && !cur->right){
            res.push_back(path);
            return;
        }
        if(cur->left) TravelPath(cur->left, path+"->", res);//隐藏的回溯,因为调用完这个TravelPath之后path的值没有变,只是传参的值变了而已。
        if(cur->right) TravelPath(cur->right, path+"->", res);
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> res;
        string path;
        if(!root) return res;
        TravelPath(root, path, res);
        return res;
    }
};
迭代法
class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> res;
        stack<TreeNode*> nodest;
        stack<string> pathst;
        if(!root) return res;
        nodest.push(root);
        pathst.push(to_string(root->val));
        while(!nodest.empty()){
            TreeNode* cur = nodest.top(); nodest.pop();
            string path = pathst.top(); pathst.pop();
            if(!cur->left && !cur->right) res.push_back(path);
            if(cur->left){
                nodest.push(cur->left);
                pathst.push(path + "->" + to_string(cur->left->val));
            }
            if(cur->right){
                nodest.push(cur->right);
                pathst.push(path + "->" + to_string(cur->right->val));
            }
        }
        return res;
    }
};

二叉树的修改与构造

翻转二叉树

LC 第226题

递归法

用的是递归?每个结点的左右子树都反过来,注意NULL的安置。

class Solution {
public:
    void Invert(TreeNode* root){
        if(root->left && root->right){
            TreeNode* tmp = root->left;
            root->left = root->right;
            root->right = tmp;
            Invert(root->left), Invert(root->right);
        }else if(root->left){
            root->right = root->left;
            root->left = NULL;
            Invert(root->right);
        }else if(root->right){
            root->left = root->right;
            root->right = NULL;
            Invert(root->left);
        }else return;
    }
    TreeNode* invertTree(TreeNode* root) {
        if(root == NULL) return root;
        Invert(root);
        return root;
    }
};

写得太麻烦啦呜呜/(ㄒoㄒ)/~~

看看官方代码!多么简洁!像话么!

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == NULL) return root;
        swap(root->left, root->right);
        invertTree(root->left);
        invertTree(root->right);
        return root;
    }
};
迭代法(深度优先)

压入栈之前一定要注意判空

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == NULL) return root;
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty()){
            TreeNode* tmp = st.top();
            st.pop();
            swap(tmp->left, tmp->right);
            if(tmp->left) st.push(tmp->left);
            if(tmp->right) st.push(tmp->right);
        }
        return root;
    }
};
迭代法(广度优先)
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == NULL) return root;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            int s = q.size();
            for(int i = 0; i < s; i++){
                TreeNode* tmp = q.front();
                q.pop();
                swap(tmp->left, tmp->right);
                if(tmp->left) q.push(tmp->left);
                if(tmp->right) q.push(tmp->right);
            }
        }
        return root;
    }
};

好长呀!呼呼!还是打算分两部分写了,字数有些超标~其实大部分的代码都是模板和套路!

唯一有些精彩的地方就是那个回溯的部份(我觉得之前是没怎么搞懂的)还有就是平衡二叉树的左右中(从下往上遍历)以及完全二叉树利用性质求结点个数那里也是十分精彩的~

总之,继续努力啦!

在这里插入图片描述
{纸短情长的爱恋}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值