刷leetcodehot100返航版--二叉树5/22、5/23

二叉树理论基础

p.s.请去acwing练一下自己创建二叉树

二叉树的种类

满二叉树和完全二叉树,二叉树搜索树

满二叉树

如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。

节点个数2^n-1【n为树的深度】

完全二叉树

在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。

满二叉树一定是完全二叉树

二叉搜索树

二叉搜索树是有数值的了,二叉搜索树是一个有序树

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉排序树

平衡二叉搜索树【AVL(Adelson-Velsky and Landis)树】

它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn【key有序】

而unordered_map、unordered_set底层实现是哈希表。

二叉树的存储方式

二叉树可以链式存储,也可以顺序存储。

那么链式存储方式就用指针, 顺序存储的方式就是用数组。

链式存储【构造二叉树:函数里面传参头指针】

数组【实际用的少】

遍历方式

DFS

中序前序后序【递归,栈;非递归,迭代】

左右中序指的是中的遍历顺序

BFS

层序遍历【迭代,队列,先进先出】

二叉树定义

struct TreeNode{

        int val;

        TreeNode* left;

        TreeNode* right;

        TreeNode(int x):val(x),left(NULL),right(NULL){}//构造函数

};

构造函数也可以不写,但是new一个新的节点的时候就比较麻烦。

例如有构造函数,定义初始值为9的节点:

TreeNode* a = new TreeNode(9);

而没有构造函数还得自己定义:

TreeNode* a = new TreeNode();
a->val = 9;
a->left = NULL;
a->right = NULL;

 二叉树遍历

递归三要素:

1.函数返回值和参数【函数头定义】2.确定结束条件【if(check)return】3.单层递归逻辑

不太懂这个结构体/二叉树怎么读进去的

1.中序遍历

94. 二叉树的中序遍历 - 力扣(LeetCode)

p.s.函数名字不要起太平常的,比如try什么的,可能和系统性的函数重名,出问题

p.s.对于返回值是void的递归函数,参数里的&是重点

感觉挺神奇的,只有root的val,也就是中可以放进数组

问题:这个输入是怎么读进去的

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {//没看懂
        //返回一个vector,必然不可以遍历
        vector<int> res;
        try1(root,res);
        return res;

        
    }
    void try1(TreeNode* root,vector<int>&res){
        if(root == nullptr){
            return;
        }
        //左中右
        try1(root->left,res);
        res.push_back(root->val);
        try1(root->right,res);

    }
};

2.迭代遍历【递归指的是一个函数可以自己调用自己】【感觉对栈不够了解,就是理解的很别扭】

【递归的本质就是栈】

一个栈【放入弹出元素】,一个数组【输出遍历顺序】

处理顺序遍历顺序

这里处理顺序定义为移除栈顶元素对其操作的顺序,遍历顺序定义为从root到left、right的操作】

栈遍历的终止条件是while(!st.empty()),不为空时进行弹出栈顶,新元素压入栈

p.s.这里要先访问左子树后访问右子树:需要先压入右节点,再压入左节点

while(!st.empty()){
            now = st.top();
            st.pop();//取出栈顶元素
            if(now!=nullptr){
                rs.push_back(now->val);//压入栈
            }else{
                continue;
            }
            st.push(now->right);
            st.push(now->left);
        }

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {//递归
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*>st;//中左右
        vector<int>rs;
        st.push(root);
        TreeNode*now;
        while(!st.empty()){
            now = st.top();
            st.pop();
            if(now!=nullptr){
                rs.push_back(now->val);
            }else{
                continue;
            }
            st.push(now->right);
            st.push(now->left);
        }
        return rs;

        
    }
};

还是不会基于迭代的后序:

中左右->中右左->result数组翻转

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
 
class Solution {//递归
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*>st;//左右
        vector<int>rs;
        st.push(root);
        TreeNode*now;
        while(!st.empty()){
            now = st.top();
            st.pop();
            if(now!=nullptr){
                
                st.push(now->left);
                st.push(now->right);
                rs.push_back(now->val);
                cout<<now->val;
            }else{
                continue;
            }
            
            
        }
        reverse(rs.begin(),rs.end());
        return rs;

        
    }
};

基于迭代的中序遍历

 【直接复制代码】

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while (cur != NULL || !st.empty()) {
            if (cur != NULL) { // 指针来访问节点,访问到最底层
                st.push(cur); // 将访问的节点放进栈
                cur = cur->left;                // 左
            } else {
                cur = st.top(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
                st.pop();
                result.push_back(cur->val);     // 中
                cur = cur->right;               // 右
            }
        }
        return result;
    }
};

层序遍历【BFS】5/22

BFS是队列

102. 二叉树的层序遍历 - 力扣(LeetCode)

问题:1.queue只取了元素:front(),没pop()

2.vector<int>s;s.push_back(1);注意:push_back是指在末尾加元素,如果构造了指定大小的vector,再push_back会发现前面有好多0,

即【3】变成【0,3】

3.注意边界条件,root为null直接返回null

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>>rs;//
        queue<TreeNode*>q;
        // q.push(root);
        if (root != NULL) q.push(root);//边界条件
        TreeNode*now;
        int size;
        int i = 0;
        int j =0;
        while(!q.empty()){           
            size =  q.size();
            
            // rs[i].resize(size);
            vector<int>re(size);
            // cout<<re.size();
            j = 0;
            while(size!=0){
                now = q.front();//没pop
                q.pop();
                re[j] = now->val;//push_back是在末尾加元素,所以导致【3】变成了[0,3],或者构建空vector,然后push_back
                j++;
                if(now->left){
                    q.push(now->left);
                }
                if(now->right){
                    q.push(now->right);
                }
                size--;
            }
            i++;
            rs.push_back(re);
        }
        return rs;  
    }
};

二叉树的最大深度【还是层序遍历bfs】 【27min】

​​​​​​e104. 二叉树的最大深度 - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int maxDepth(TreeNode* root) {//层次遍历??
        int depth = 0;
        queue<TreeNode*>q;
        if(root==nullptr){
            return 0;
        }
        q.push(root);
        while(!q.empty()){
            int size = q.size();
            depth++;
            while(size!=0){
                TreeNode*cur = q.front();
                q.pop();
                if(cur->left!=nullptr){
                    q.push(cur->left);
                }
                if(cur->right!=nullptr){
                    q.push(cur->right);
                }
                size--;
            }
        }
        return depth;
        
    }
};

翻转二叉树【8min】5/22

有时间可细品,经典题

注意如果按中序方式遍历的话

需要

 inverse1(root->left);

        swap(root->left,root->right);

        inverse1(root->left);【依然还是root->left】【因为翻转了,所以原来的right变成left了】

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == nullptr){
            return nullptr;
        }
        //核心在于left,right进行swap,那么遍历每一个节点?yes
        
        inverse1(root);
        return root;
    }
    void inverse1(TreeNode* root){
        if(root==nullptr){
            return;
        }
        swap(root->left,root->right);
        inverse1(root->left);
        inverse1(root->right);
    }
};

3.对称二叉树5/23【没思路】【迷茫】【1h】

这个递归和之前的不太一样,原来的是一直往深遍历,直到什么情况retrun

这里更像是从根出发就开始return了,其实也不是,还是到底才开始return,只不过根有情况直接在刚开始就return掉了

方法一、递归

这里是一个不返回void的递归!!!

注意:空树的边界情况!!!!

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool compare(TreeNode* left,TreeNode*right){//自上而下
        if(left==nullptr && right==nullptr){
            return true;
        }else if(left ==nullptr && right!=nullptr){
            return false;
        }else if(left!= nullptr &&right==nullptr){
            return false;
        }else if(left->val != right->val){//不为空
            return false;
        }
        bool oo = compare(left->left,right->right);
        bool ii = compare(left->right,right->left);
        if(oo && ii){
            return true;
        }else{
            return false;
        }
    }
    bool isSymmetric(TreeNode* root) {
        //没啥思路,层序遍历?不保真
        //没看懂的点在于如何考虑以下情况
        //   8    8
        //  /      \
        //2          2 
        //这个的思路应该是从上向下,和一般的递归不太一样
        if (root == NULL) return true;//考虑空树
        bool it = compare(root->left,root->right);
        return it;
    }
};

另一种实现:queue迭代

【感觉queue还是要比stack舒服一点】

p,s.队列可以存储 nullptr,支持push和front等

错误:左右子树都为nullptr时应该continue,而不是return true

因为这时候queue里也许还有别的值

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(root==nullptr){
            return true;
        }
        queue<TreeNode*>q;
        q.push(root->left);
        q.push(root->right);
        while(!q.empty()){
            TreeNode *left = q.front();q.pop();
            TreeNode *right= q.front();q.pop();
            
            if(left == nullptr && right==nullptr){//不应该return true
                // return true;
                continue;
            }else if(left == nullptr && right!=nullptr){
                return false;
            }else if(left != nullptr && right==nullptr){
                return false;
            }
            if(left->val == right->val){
                q.push(left->left);
                q.push(right->right);
                q.push(left->right);
                q.push(right->left);
            }else{
                return false;
            }
        }
        return true;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值