刷题记录-树,二叉树

剑指Offer(三十五):复杂链表的复制(重要)

面试题35. 复杂链表的复制
难度中等46
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例 1:

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

提示:
• -10000 <= Node.val <= 10000
• Node.random 为空(null)或指向链表中的节点。
• 节点数目不超过 1000 。
三步法:
1、把复制的结点链接在原始链表的每一对应结点后面
2、把复制的结点的random指针指向被复制结点的random指针的下一个结点
3、拆分成两个链表,奇数位置组成原链表,偶数位置组成复制链表

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/
class Solution {
public:
    Node* copyRandomList(Node* head) {
        //1、把复制的结点链接在原始链表的每一对应结点后面 //复制next 如原来是A->B->C 变成A->A'->B->B'->C->C'
        if(head==NULL) return NULL;
        Node* node=head;
        while(node){
            Node* tmp=new Node(node->val);
            tmp->next=node->next;
            node->next=tmp;
            node=tmp->next;
        }
        //2、把复制的结点的random指针指向被复制结点的random指针的下一个结点 //复制random:cur是原来链表的结点 cur->next是复制cur的结点
        node=head;
        while(node){
            Node* temp=node->next;
            if(node->random){
                temp->random=node->random->next;
            }
            node=temp->next;

        }
        // 拆分链表,将链表拆分为原链表和复制后的链表
        node=head;
        Node* p=head->next;
        while(node){
            Node* temp=node->next;
            node->next=temp->next;
            if(temp->next!=NULL){
                temp->next=temp->next->next;
            }
            node=node->next;
        }
        return p;
        
    }
};

剑指Offer(三十六):二叉搜索树与双向链表(重要)

面试题36. 二叉搜索树与双向链表
难度中等54收藏分享切换为英文关注反馈
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
方法一:中序遍历

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;

    Node() {}

    Node(int _val) {
        val = _val;
        left = NULL;
        right = NULL;
    }

    Node(int _val, Node* _left, Node* _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
public:
    Node* treeToDoublyList(Node* root) {
        if(root == NULL)
            return NULL;
        Node* head = NULL;
        Node* pre = NULL;// 定义一个pre指针
        helper(root,head,pre);
        head->left = pre;
        pre->right = head;
        return head;
    }
    void helper(Node* root,Node* &head,Node* &pre){// 中序遍历
        if(root==NULL) return;
        helper(root->left,head,pre);// 先递归遍历左子树

        if(head==NULL){
            head=root;
            pre=root;
        }
        else
        {
            root->left=pre;// 修改为双向链表
            pre->right=root;
            pre=root;//更新双向链表尾结点
        }

        helper(root->right,head,pre);// 再递归遍历右子树
    }
};

剑指Offer(三十七):序列化二叉树(重要)

面试题37. 序列化二叉树
难度困难37收藏分享切换为英文关注反馈
请实现两个函数,分别用来序列化和反序列化二叉树。
示例:
你可以将以下二叉树:

1

/
2 3
/
4 5
序列化为 “[1,2,3,null,null,4,5]”

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if (root == NULL)
            return "#_";
        string res = to_string(root->val) + "_";
        res += serialize(root->left);
        res += serialize(root->right);
        return res;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        std::stringstream ss(data);
        std::string item;
        queue<string> q;
        while (std::getline(ss, item, '_')) 
            q.push(item);
        return helper(q);
    }
    TreeNode* helper(queue<string>& q)
    {
        string val = q.front();
        q.pop();
        if (val == "#")
            return NULL;
        TreeNode* head = new TreeNode(stoi(val));
        head->left = helper(q);
        head->right = helper(q);
        return head;
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

剑指Offer(五十四):二叉搜索树的第k个结点(重要)

面试题54. 二叉搜索树的第k大节点
难度简单32
给定一棵二叉搜索树,请找出其中第k大的节点。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/
1 4

2
输出: 4
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/
3 6
/
2 4
/
1
输出: 4
限制:
1 ≤ k ≤ 二叉搜索树元素个数
MySolution:

/**
 * 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:
    void dfs(TreeNode *root,vector<int> & res){
        if(root==NULL) return;
        if(root->left) dfs(root->left,res);
        res.push_back(root->val);
        if(root->right) dfs(root->right,res);
    }
    int kthLargest(TreeNode* root, int k) {
        vector<int> res;
        dfs(root,res);
        return res[res.size()-k];

    }
};

方法一:递归

/**
 * 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 res=0;
int cnt=0;

void dfs(TreeNode* root,int k){
    if(root==NULL) return;
    dfs(root->right,k);
    if(++cnt==k){
        res=root->val;
        return;
    }
    dfs(root->left,k);
}
    int kthLargest(TreeNode* root, int k) {
        if(root==NULL||k<1) return 0;
        dfs(root,k);
        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:
    int kthLargest(TreeNode* root, int k) {
        int n=0;
        stack<TreeNode*> s;
        TreeNode* p = root;
        while (!s.empty() || p!=NULL)
        {
            while(p!=NULL)
            {
                s.push(p);
                p = p->right;
            }
            p =s.top();
            s.pop();
            if (++n==k)
            {
                return p->val;
            }
            p = p->left;
        }
        return 0;

    }
};

剑指Offer(五十五):二叉树的深度(重要)

面试题55 - I. 二叉树的深度
难度简单25
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最大深度 3 。
提示:

  1. 节点总数 <= 10000
    推荐用递归,取左右子树最大的深度加上1
    两种方法:可以是递归的方法,属于DFS(深度优先搜索);另一种方法是按照层次遍历,属于BFS(广度优先搜索)。
    Mysolution:
/**
 * 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;
        return max(maxDepth(root->left),maxDepth(root->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:
    int maxDepth(TreeNode* root) {
        if(root==NULL) return 0;
        queue<TreeNode*> q;
        q.push(root);
        int depth=0;
        while(!q.empty()){
            int len=q.size();
            TreeNode* tmp;
            
            int i=0;
            while(i++<len){
                tmp=q.front();
                q.pop();
                if(tmp->left) q.push(tmp->left);
                if(tmp->right) q.push(tmp->right);
            }
            depth++;
        }
        return depth;

    }
};

剑指Offer(五十五):平衡二叉树(重要)

面试题55 - II. 平衡二叉树
难度简单29
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/
9 20
/
15 7
返回 true 。

示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/
2 2
/
3 3
/
4 4
返回 false 。

限制:
• 1 <= 树的结点个数 <= 10000
Mysolution:

/**
 * 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 treeDepth(TreeNode* root){
        if(root==NULL) return 0;
        return max(treeDepth(root->left),treeDepth(root->right))+1;
    }
    bool isBalanced(TreeNode* root) {
        if(root==NULL) return true;
        int leftDepth=treeDepth(root->left);
        int rigthDepth=treeDepth(root->right);
        if(leftDepth-rigthDepth>1||leftDepth-rigthDepth<-1) return false;
        return isBalanced(root->left)&&isBalanced(root->right);

    }
};

解题思路有两种,只遍历一次的方法最优。
重复遍历多次:自顶向下
时间复杂度O(nlogn), 空间复杂度O(n)复杂度分析
自顶向下在遍历树的每个结点的时候,调用函数TreeDepth得到它的左右子树的深度。如果每个结点的左右子树的深度相差都不超过1,则这是一颗平衡的二叉树。这种方法的缺点是,首先判断根结点是不是平衡的,需要使用TreeDepth获得左右子树的深度,然后还需要继续判断子树是不是平衡的,还是需要使用TreeDepth获得子树的左右子树的深度,这样就导致了大量的重复遍历。
只遍历一次:自底向上
时间复杂度O(n), 空间复杂度O(n)复杂度分析
自底向上与自顶向下的逻辑相反,首先判断子树是否平衡,然后比较子树高度判断父节点是否平衡。检查子树是否平衡。如果平衡,则使用它们的高度判断父节点是否平衡,并计算父节点的高度。自底向上计算,每个子树的高度只会计算一次。可以递归先计算当前节点的子节点高度,然后再通过子节点高度判断当前节点是否平衡,从而消除冗余。
方法二:

class Solution {
public:

    bool isBalanced(TreeNode* root) {
        if (root == NULL)
            return true;
        int depth = 0;
        return helper(root, depth);
    }
    bool helper(TreeNode* root, int &depth)
    {
        if (root == NULL)
        {
            depth = 0;
            return true;
        }
        int left, right;
        if (helper(root->left, left) && helper(root->right, right) && abs(left-right)<=1)
        {
            depth = max(left,right)+1;
            return true;
        }
        return false;
    }
};

LeetCode(94):二叉树的中序遍历(重要)

  1. 二叉树的中序遍历
    难度中等531
    给定一个二叉树,返回它的中序 遍历。
    示例:
    输入: [1,null,2,3]
    1

    2
    /
    3

输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
递归与迭代两种方法
方法一:递归
中序遍历:左子树—> 根结点 —> 右子树,比较容易利用递归写出
方法二:迭代
根据中序遍历的顺序,优先访问左子树,然后在访问根节点和右子树。所以,对于任意结点node,第一部分即直接访问之,之后在判断左子树是否为空,不为空时即重复上面的步骤,直到其为空。若为空,则需要访问右子树。注意,在访问过左孩子之后,需要反过来访问其右孩子,所以,需要栈这种数据结构的支持。对于任意一个结点node,具体步骤如下:
a)访问之,并把结点node入栈,当前结点置为左孩子;
b)判断结点node是否为空,若为空,则取出栈顶结点并出栈,将右孩子置为当前结点;否则重复a)步直到当前结点为空或者栈为空(可以发现栈中的结点就是为了访问右孩子才存储的)
/**

  • 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> res;
    void dfs(TreeNode* root){
        if(root==NULL) return;
        dfs(root->left);
        res.push_back(root->val);
        dfs(root->right);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        dfs(root);
        return res;              
    }
};
//方法二:迭代
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
/*栈S;
p= root;
while(p || S不空){
    while(p){
        p入S;
        p = p的左子树;
    }
    p = S.top 出栈;
    访问p;
    p = p的右子树;
}
*/
        stack<TreeNode*> s;
        vector<int> res;
        if(root==NULL) return res;
        TreeNode* cur=root;
        //s.push(root);
        while(!s.empty()||cur!=NULL){
            while(cur!=NULL){
                s.push(cur);
                cur=cur->left;
            }
            cur=s.top();
            s.pop();
            res.push_back(cur->val);
            cur=cur->right;
        }
        return res;
        
    }
};

LeetCode(144):二叉树的前序遍历(重要)

  1. 二叉树的前序遍历
    难度中等280
    给定一个二叉树,返回它的 前序 遍历。
    示例:
    输入: [1,null,2,3]
    1

    2
    /
    3

输出: [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:
    void dfs(TreeNode* root,vector<int> &res){
        if(root==NULL) return;
        res.push_back(root->val);
        dfs(root->left,res);
        dfs(root->right,res);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        if(root==NULL) return res;
        dfs(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<int> preorderTraversal(TreeNode* root) {
/*栈S;
p= root;
while(p || S不空){
    while(p){
        访问p节点;
        p的右子树入S;
        p = p的左子树;
    }
    p = S栈顶弹出;
}
*/
    vector<int> res;
    if(root==NULL) return res;
    stack<TreeNode*> s;
    TreeNode* p=root;
    while(p||!s.empty()){
        while(p){
            res.push_back(p->val);
            s.push(p->right);
            p=p->left;
        }
        p=s.top();
        s.pop();
    }
    return res;

    }
};

迭代法:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        if (root==NULL)
            return res;
        stack<TreeNode*> s;
        s.push(root);
        while (!s.empty())
        {
            TreeNode* node = s.top();
            s.pop();
            res.push_back(node->val);
            if (node->right)
            {
                s.push(node->right);
            }
            if (node->left)
            {
                s.push(node->left);
            }
            
        }
        return res;
    }
};

LeetCode(145):二叉树的后序遍历(重要)

  1. 二叉树的后序遍历
    难度困难327收藏分享切换为英文关注反馈
    给定一个二叉树,返回它的 后序 遍历。
    示例:
    输入: [1,null,2,3]
    1

    2
    /
    3

输出: [3,2,1]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
递归与迭代两种方法
方法一:递归
后序遍历:左子树 —> 右子树 —> 根结点,比较容易利用递归写出
方法二:迭代
使用栈(先进后出)来完成,我们先将根节点放入栈中,从根节点开始,每次迭代弹出当前栈顶元素,并将其孩子节点压入栈中,先压左子树再压右子树,然后在调用reverse函数。
使用一个指针lastVisited记录最后访问的节点,一个根节点被访问的前提是:无右子树或右子树已被访问过。/**

  • 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:
    void dfs(TreeNode* root,vector<int> &res){
        if(root==NULL) return;
        dfs(root->left,res);
        dfs(root->right,res);
        res.push_back(root->val);
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        if(root==NULL) return res;
        dfs(root,res);
        return res;

    }
};

方法二:迭代

//前序遍历之后reverse
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        if(root==NULL) return res;
        stack<TreeNode*> s;
        TreeNode* p=root;
        while(!s.empty()||p){
            while(p){
                res.push_back(p->val);
                s.push(p->left);
                p=p->right;
            }
            p=s.top();
            s.pop();

        }
        reverse(res.begin(),res.end());
        return res;

    }
};

按照左子树-根-右子树的方式,将其转换成迭代方式。
思路:每到一个节点 A,因为根要最后访问,将其入栈。然后遍历左子树,遍历右子树,最后返回到 A。
但是出现一个问题,无法区分是从左子树返回,还是从右子树返回。
因此,给 A 节点附加一个标记T。在访问其右子树前,T 置为 True。之后子树返回时,当 T 为 True表示从右子树返回,否则从左子树返回。
当 T 为 false 时,表示 A 的左子树遍历完,还要访问右子树。
同时,当 T 为 True 时,表示 A 的两棵子树都遍历过了,要访问 A 了。并且在 A 访问完后,A 这棵子树都访问完成了。
栈S;

p= root;
T<节点,True/False> : 节点标记;
while(p || S不空){
while§{
p入S;
p = p的左子树;
}
while(S不空 且 T[S.top] = True){
访问S.top;
S.top出S;
}
if(S不空){
p = S.top 的右子树;
T[S.top] = True;
}
}

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        if (root==NULL) return res;
        stack<TreeNode*> s;
        TreeNode* p = root;
        TreeNode* lastVisited = NULL;
        while(!s.empty() || p)
        {
            while(p)
            {
                s.push(p);
                p = p->left;
            }
            p = s.top();
            if (p->right == NULL || p->right == lastVisited)
            {
                res.push_back(p->val);
                s.pop();
                lastVisited = p;
                p = NULL; // p 已经访问过了,没用了设置为NULL
            }
            else
            {
                p = p->right;
            }
        }
        return res;

    }
};

LeetCode(98):验证搜索二叉树(重要)

  1. 验证二叉搜索树
    难度中等620收藏分享切换为英文关注反馈
    给定一个二叉树,判断其是否是一个有效的二叉搜索树。
    假设一个二叉搜索树具有如下特征:
    • 节点的左子树只包含小于当前节点的数。
    • 节点的右子树只包含大于当前节点的数。
    • 所有左子树和右子树自身必须也是二叉搜索树。
    示例 1:
    输入:
    2
    /
    1 3
    输出: true
    示例 2:
    输入:
    5
    /
    1 4
    /
    3 6
    输出: false
    解释: 输入为: [5,1,4,null,null,3,6]。
    根节点的值为 5 ,但是其右子节点值为 4 。
    二叉搜索树的中序遍历为升序,中序遍历搜索树后判断 是否是严格升序
    方法一:
/**
 * 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:
    void dfs(TreeNode* root,vector<int> &res){
        if(root==NULL) return;
        dfs(root->left,res);
        res.push_back(root->val);
        dfs(root->right,res);
    }
    bool isValidBST(TreeNode* root) {
        vector<int> res;
        dfs(root,res);
        set<int> t(res.begin(),res.end());
        vector<int> tmp;
        tmp.assign(t.begin(),t.end());
        return tmp==res;

        return true;
        
    }
};

方法二:

/**
 * 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* pre=NULL;
    bool isValidBST(TreeNode* root) {
        if(root==NULL) return true;
        if(!isValidBST(root->left)) return false;// 访问左子树, 如果左子树为false 返回false
        if(pre&&pre->val>=root->val) return false; // 访问当前节点:如果当前节点小于等于中序遍历的前一个节点,说明不满足BST,返回 false;否则继续遍历。
        pre=root;// 更新前一个节点
        //if(!isValidBST(root->right)) return false;// 访问右子树
        return isValidBST(root->right);
        
    }
};

LeetCode(199):二叉树的右视图(重要,BFS)

  1. 二叉树的右视图
    难度中等256收藏分享切换为英文关注反馈
    给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
    示例:
    输入: [1,2,3,null,5,null,4]
    输出: [1, 3, 4]
    解释:

1 <—
/
2 3 <—
\
5 4 <—
方法0:

/**
 * 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> rightSideView(TreeNode* root) {
        if(root==NULL) return vector<int>();
        vector<int> res;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            int len=q.size();
            res.push_back(q.back()->val);
            int i=0;
            TreeNode* tmp;
            while(i<len){
                tmp=q.front();
                q.pop();
                if(tmp->left) q.push(tmp->left);
                if(tmp->right) q.push(tmp->right);
                i++;
            }
        }
        return res;

    }
};

方法二:
BFS
按层来遍历,先遍历每一层的右子树

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

    }
};

DFS
按照根节点-右子树-左子树来遍历,逆前序遍历

/**
 * 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:
    void dfs(TreeNode* root,int depth,vector<int> &res){
        if(root==NULL) return;
        if(depth==res.size()){
            res.push_back(root->val);// 利用结果res的size等于tree的高度的性质
        } 
        dfs(root->right,depth+1,res);
        dfs(root->left,depth+1,res);
    }
    vector<int> rightSideView(TreeNode* root) {
        vector<int> res;
        dfs(root,0,res);
        return res;

    }
};

LeetCode(543):二叉树的直径(重要,利用二叉树的深度公式)

  1. 二叉树的直径
    难度简单378收藏分享切换为英文关注反馈
    给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
    示例 :
    给定二叉树
    1
    /
    2 3
    / \
    4 5
    返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
    注意:两结点之间的路径长度是以它们之间边的数目表示。
    二叉树的直径不一定过根节点,因此需要去搜一遍所有子树(例如以root,root.left, root.right…为根节点的树)对应的直径,取最大值。
    root的直径 = root左子树高度 + root右子树高度
    root的高度 = max {root左子树高度, root右子树高度} + 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 res=0;
    int dfs(TreeNode* root){// 函数dfs的作用是:找到以root为根节点的二叉树的最大深度
        if(root==NULL) return 0;
        int leftDepth=dfs(root->left);
        int rightDepth=dfs(root->right);
        res=max(res,leftDepth+rightDepth);
        return max(leftDepth,rightDepth)+1;

    }
    int diameterOfBinaryTree(TreeNode* root) {
        if(root==NULL) return res;
        dfs(root);
        return res;
    }
};

LeetCode(236):二叉树的最近公共祖先(重要)

  1. 二叉树的最近公共祖先
    难度中等604收藏分享切换为英文关注反馈
    给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
    百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
    例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
• 所有节点的值都是唯一的。
• p、q 为不同节点且均存在于给定的二叉树中。
递归
考虑通过递归对二叉树进行后序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p, q, 在节点 root的异侧时,节点root即为最近公共祖先,则向上返回root。

/**
 * 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 (root==NULL ||root==p || root==q) return root;
        TreeNode* left = lowestCommonAncestor(root->left,p,q);
        TreeNode* right = lowestCommonAncestor(root->right,p,q);
        if (left == NULL && right == NULL) return NULL;  // 左右子树同时为空,都不包含p,q,返回NULL
        if (left==NULL) return right;  // 当 left为空 ,right不为空 :p,q都不在root的左子树中,直接返回 right
        if (right==NULL) return left;  // 与上一条件类似
        return root;  // 同时不为空,说明p,q在左右子树异侧,返回root
        
    }
};

LeetCode(572):另一个树的子树(重要,递归)

  1. 另一个树的子树
    难度简单296收藏分享切换为英文关注反馈
    给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
    示例 1:
    给定的树 s:
    3
    /
    4 5
    /
    1 2
    给定的树 t:
    4
    /
    1 2
    返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。
    示例 2:
    给定的树 s:
    3
    /
    4 5
    /
    1 2
    /
    0
    给定的树 t:
    4
    /
    1 2
    返回 false。
    判断镜像二叉树类似,一个树是另一个树的子树 则
    要么这两个树相等
    要么这个树是左树的子树
    要么这个树hi右树的子树
/**
 * 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 helper(TreeNode* s, TreeNode* t){
    if(s==NULL&&t==NULL) return true;
    /*
    if(s&&t&&s->val==t->val) return helper(s->left,t->left)&&helper(s->right,t->right);
    else return false;
    */
    return s&&t && s->val==t->val && helper(s->left, t->left) && helper(s->right,t->right);

}
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(s==NULL&&t!=NULL) return false;
        if(s==NULL&&t==NULL) return true;
        return helper(s,t)||isSubtree(s->left,t)||isSubtree(s->right,t);

        
    }
};

剑指Offer(三十四):二叉树中和为某一值的路径(重要)

面试题34. 二叉树中和为某一值的路径
难度中等42
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/
4 8
/ /
11 13 4
/ \ /
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
示:

  1. 节点总数 <= 10000
    典型的带记忆的DFS来解决
    思路:
    递归前序遍历树, 把结点加入路径。
    若该结点是叶子结点则比较当前路径和是否等于期待和。
    弹出结点,每一轮递归返回到父结点时,当前路径也应该回退一个结点
/**
 * 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:
    void dfs(TreeNode* root, int sum,vector<vector<int>> &res,vector<int> &out){
        if(root==NULL) return ;
        out.push_back(root->val);
        // 如果是叶节点,并且路径上的节点值的和为输入的值,就像结果中添加这一out
        if(sum==root->val&&root->left==NULL&&root->right==NULL){
            res.push_back(out);
        }// 不是叶节点就遍历他的子节点
        dfs(root->left,sum-root->val,res,out);
        dfs(root->right,sum-root->val,res,out);
        out.pop_back();// 到这一步说明不满足要求,要返回父节点,需要删除路径上的当前节点

    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> res;
        vector<int> out;
        dfs(root,sum,res,out);
        return res;

    }
};

剑指Offer(三十三):二叉搜索树的后序遍历序列(重要)

面试题33. 二叉搜索树的后序遍历序列
难度中等56
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

参考以下这颗二叉搜索树:
5
/
2 6
/
1 3
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true

提示:

  1. 数组长度 <= 1000
    已知条件:后序序列最后一个值为root;二叉搜索树左子树值都比root小,右子树值都比root大。
    1、确定root;
    2、遍历序列(除去root结点),找到第一个大于root的位置,则该位置左边为左子树,右边为右子树;
    3、遍历右子树,若发现有小于root的值,则直接返回false;
    4、分别判断左子树和右子树是否仍是二叉搜索树(即递归步骤1、2、3)。
class Solution {
public:

    bool helper(vector<int>& postorder,int start,int end){
        if(start>end) return false;
        int root=postorder[end];
        int i=start;
        while(i<end){
            if(postorder[i]>root){
                break;
            }
            i++;
        }
        for(int j=i;j<end;j++){
            if(postorder[j]<root) return false;
        }
        //判断左子树是不是二叉搜索树
        bool left = true;
        if (i>start)
        {
            left = helper(postorder, start, i-1);
        }
        
        //判断右子树是不是二叉搜索树
        bool right = true;
        if (i < end-1)
        {
            right = helper(postorder, i, end-1);
        }
        return left && right;
        //return helper(postorder,start,i-1)&&helper(postorder,i,end-1);

    }
    bool verifyPostorder(vector<int>& postorder) {
        bool res=true;
        if(postorder.empty()) return res;
        int len=postorder.size();
        res=helper(postorder,0,len-1);
        return res;

    }
};

剑指Offer(三十二):之字形打印二叉树(重要,利用双端队列实现前取后放,后取前放)

面试题32 - III. 从上到下打印二叉树 III
难度中等19
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回其层次遍历结果:
[
[3],
[20,9],
[15,7]
]

提示:

  1. 节点总数 <= 1000
    因为奇偶层的打印顺序不一样是相反的,可以用reverse来解决,但是海量数据时这个效率很低。

因为奇数层的打印顺序是从左到右,偶数层的打印顺序是从右到左,可以利用STL容器deque中push_back(),push_front(),front(),back(),pop(),popfront()来解决,实现前取后放,后取前放,因为deque队列中的元素,都是从左到右的,当zigzag==true;,从左到右打印,就从前边开始取出元素,下一层的元素从后边压入,同理,从右向左打印时,从后边取出元素,下一层的元素就从前边压入,注意先压入右子树的,后压入左子树,这样新的队列还是从左到右,然后继续,直至队列为空。

/**
 * 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<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(root==NULL) return res;
        deque<TreeNode*> dq;
        dq.push_front(root);
        int level=0;
        while(!dq.empty()){
            int len=dq.size();
            vector<int> temp(len);
            TreeNode* tmp;
            for(int i=0;i<len;++i){//注意&&优先级,加括号!!!
                if((level&1)==0){//前取后放:从左向右,所以从前边取,后边放入
                    tmp=dq.front();
                    dq.pop_front();
                    temp[i]=tmp->val;
                    if(tmp->left) dq.push_back(tmp->left);
                    if(tmp->right) dq.push_back(tmp->right);
                }else{// 后取前放:从右向左,从后边取,前边放入
                    tmp=dq.back();
                    dq.pop_back();
                    temp[i]=tmp->val;
                    if(tmp->right) dq.push_front(tmp->right);
                    if(tmp->left) dq.push_front(tmp->left);
                }
                
                
            }
            level++;
            res.push_back(temp);

        }
        return res;

    }
};

剑指Offer(三十二):分行从上往下打印二叉树(重要)

面试题32 - II. 从上到下打印二叉树 II
难度简单25
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]

提示:

  1. 节点总数 <= 1000
    方法一:迭代
    同样借助队列实现,不过注意,与之前不同,此题要注意计算出当前层有多少个元素:等于队列的长度,按照顺序遍历完队列加入out中。
    第 0 层只包含根节点 root,算法实现如下:
    • 初始化队列只包含一个节点 root。
    • 当队列非空的时候:
    o 计算当前层有多少个元素:等于队列的长度。
    o 初始化一个空列表out
    o 利用循环将这些元素从队列中弹出,并加入out空列表中。
    o 将他们的孩子节点作为下一层压入队列中。
    o 将out列表加入res中,进入下一层。
    方法二:递归
    递归,首先确认树非空,然后调用递归函数 helper(node, level),参数是当前节点和节点的层次。程序过程如下:
    • 输出为 res,当前最高层数就是res的长度 res.size()。比较访问节点所在的层次 level 和当前最高层次 res.size() 的大小(当前所在层次level始终是不大于当前最高层次res.size()的),如果level == res.size()了,就向res添加一个空res.push_back(vector())。
    • 将当前节点插入到对应层的列表 res[level] 中。
    • 递归非空的孩子节点:helper(node->left / node->right, level + 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:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(root==NULL) return res;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            int len=q.size();
            vector<int> temp(len);
            TreeNode* tmp;
            for(int i=0;i<len;++i){
                tmp=q.front();
                q.pop();
                temp[i]=tmp->val;
                if(tmp->left) q.push(tmp->left);
                if(tmp->right) q.push(tmp->right);

            }
            res.push_back(temp);
        }
        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<vector<int>> res;
    void helper(TreeNode* root,int level){
        if(root==NULL) return;
        if(res.size()==level){
            res.push_back(vector<int>());
        }
        res[level].push_back(root->val);
        if(root->left) helper(root->left,level+1);
        if(root->right) helper(root->right,level+1);

    }

    vector<vector<int>> levelOrder(TreeNode* root) {
        
        if(root==NULL) return res;
        helper(root,0);
        return res;

    }
};

剑指Offer(二十八):对称的二叉树(重要)

面试题28. 对称的二叉树
难度简单42
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/
2 2
/ \ /
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/
2 2
\
3 3

示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false

限制:
0 <= 节点个数 <= 1000
思路:递归
1.怎么判断一棵树是不是对称二叉树? 答案:如果所给根节点,为空,那么是对称。如果不为空的话,当他的左子树与右子树对称时,他对称
2.那么怎么知道左子树与右子树对不对称呢?在这我直接叫为左树和右树 答案:如果左树的左孩子与右树的右孩子对称,左树的右孩子与右树的左孩子对称,那么这个左树和右树就对称。
那用递归分别比较左右子树
递归结束条件:
都为空指针则返回 true
只有一个为空则返回 false
两个指针当前节点值不相等 返回false
递归过程:
判断 A 的右子树与 B 的左子树是否对称
判断 A 的左子树与 B 的右子树是否对称
方法一:递归

/**
 * 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 helper(TreeNode* left,TreeNode* right){
        if(left==NULL&&right==NULL) return true;// 先写递归终止条件
        if(left==NULL&&right) return false;// 如果其中之一为空,也不是对称的
        if(left&&right==NULL) return false;
        if(left->val!=right->val) return false;
        return helper(left->left,right->right)&&helper(left->right,right->left);// 前序遍历
    }
    bool isSymmetric(TreeNode* root) {
        bool res=true;
        if(root==NULL) return true;
        if(root) res=helper(root->left,root->right);        
        return res;
    }
};

剑指Offer(二十七):二叉树的镜像(重要)

面试题27. 二叉树的镜像
面试题27. 二叉树的镜像
难度简单25
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
例如输入:
4
/
2 7
/ \ /
1 3 6 9
镜像输出:
4
/
7 2
/ \ /
9 6 3 1
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
限制:
0 <= 节点个数 <= 1000

/**
 * 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* mirrorTree(TreeNode* root) {
        if(root==NULL) return NULL;
        TreeNode* res=new TreeNode(root->val);
        res->left=mirrorTree(root->right);
        res->right=mirrorTree(root->left);
        return res;

    }
};

剑指Offer(二十六):树的子结构(重要)

面试题26. 树的子结构
难度中等55
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
例如:
给定的树 A:
3
/
4 5
/
1 2
给定的树 B:
4
/
1
返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。
示例 1:
输入:A = [1,2,3], B = [3,1]
输出:false
示例 2:
输入:A = [3,4,5,1,2], B = [4,1]
输出:true
限制:
0 <= 节点个数 <= 10000
思路:首先现在A中找出B的根节点,也就是要遍历A找出与B根节点相同的值,然后判断树A中以R为根节点的子树是否包含和B一样的结构。 根节点值相等就继续判断剩余子树是否相等,直到B为NULL。

/**
 * 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 helper(TreeNode* A,TreeNode*B){
        if(B==NULL) return true;//B已经遍历完了都能对应的上
        if(A==NULL) return false;//A完B未完
        if(A->val!=B->val) return false;//如果其中有一个点没有对应上,返回false
        return helper(A->left,B->left)&&helper(A->right,B->right);//如果根节点对应的上,那么就分别去子节点里面匹配
    }
    bool isSubStructure(TreeNode* A, TreeNode* B) {
        bool res=false;
        if(A&&B){//当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false
            if(A->val==B->val)res= helper(A,B);//如果找到了对应B的根节点的点,
            if(!res) res=isSubStructure(A->left,B);//如果找不到,那么就再去A的左子树当作起点
            if(!res) res=isSubStructure(A->right,B);//如果找不到,那么就再去A的右子树当作起点
        }
        return res;

    }
};

剑指Offer(七):重建二叉树(重要)

面试题07. 重建二叉树
难度中等108收藏分享切换为英文关注反馈
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/
9 20
/
15 7

限制:
0 <= 节点个数 <= 5000
思路分析:利用二叉树各种遍历的特点,找到根节点和左右子树 ,递归重建。注意前序遍历中的第一个数字是根节点的值,在中序遍历中根节点的值在序列中间,左子树的节点的值在根节点的值的左边,而右子树的节点的值位于根节点的右边,所以先扫描中序遍历,找到根节点所在位置,然后找到左子树和右子树的前序遍历和中序遍历即可。
方法一:递归一

/**
 * 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* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.empty()||inorder.empty()) return NULL;
        int val=preorder[0];// 前序遍历的第一个数字是根节点的值
        TreeNode* root=new TreeNode(val);// 创建根节点
        if(preorder.size()==1) return root;// 如果长度为1,直接返回根节点
        int rootIndex=0;// 找到root所在的位置,确定好前序和中序中左子树和右子树序列的范围
        for(int i=0;i<inorder.size();++i){
            if(inorder[i]==val){
                rootIndex=i;
                break;
            }
        }
        vector<int> leftPre,leftIn,rightPre,rightIn;
        for(int i=0;i<rootIndex;++i){
            leftPre.push_back(preorder[i+1]);// +1 是因为前序遍历的第一个节点是根节点
            leftIn.push_back(inorder[i]);
        }
        for(int i=rootIndex+1;i<preorder.size();++i){
            rightPre.push_back(preorder[i]);
            rightIn.push_back(inorder[i]);

        }

        root->left=buildTree(leftPre,leftIn);
        root->right=buildTree(rightPre,rightIn);
        return root;


    }
};

递归二:

class Solution {
public:
TreeNode *helper(vector<int> preorder,int preStart,int preEnd,vector<int> inorder,int inStart,int inEnd){  
    if(preStart>=preEnd||inStart>=inEnd) return NULL;/
    TreeNode* root=new TreeNode(preorder[preStart]);
    int rootIndex=0;
    while(inorder[rootIndex]!=preorder[preStart]){
        rootIndex++;
    }
    cout<<rootIndex<<endl;
    root->left=helper(preorder,preStart+1,preStart+1+rootIndex-inStart,inorder,inStart,rootIndex);
    root->right=helper(preorder,preStart+1+rootIndex-inStart,preEnd,inorder,rootIndex+1,inEnd);    
    return root;
}
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size()<=0) return NULL;
    //前序遍历的第一个值是根节点的值,对应中序遍历同一个值
    TreeNode *root=new TreeNode(preorder[0]);
    return helper(preorder,0,preorder.size(),inorder,0,inorder.size());
    }
};

极简递归:

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
       //
       return recursionBuild(preorder.begin(),preorder.end(),inorder.begin(),inorder.end());

    }
    TreeNode* recursionBuild(vector<int>::iterator preBegin,vector<int>::iterator preEnd,vector<int>::iterator inBegin,vector<int>::iterator inEnd)
    {
        if(inEnd==inBegin) return NULL;
        TreeNode* cur=new TreeNode(*preBegin);
        auto root=find(inBegin,inEnd,*preBegin);
        cur->left=recursionBuild(preBegin+1,preBegin+(root-inBegin)+1,inBegin,root);
        cur->right=recursionBuild(preBegin+1+(root-inBegin),preEnd,root+1,inEnd);
        return cur;
    }
};

剑指Offer八:二叉树的下一个节点(重要)

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路分析:

我们以上图为例进行讲解,上图二叉树的中序遍历是d,b,h,e,i,a,f,c,g。我们以这棵树为例来分析如何找出二叉树的下一个结点。
如果一个结点有右子树,那么它的下一个结点就是它的右子树的最左子结点。也就是说从右子结点出发一直沿着指向左子树结点的指针,我们就能找到它的下一个结点。例如,图中结点b的下一个结点是h,结点a的下一个结点是f。
接着我们分析一下结点没有右子树的情形。如果结点是它父结点的左子结点,那么它的下一个结点就是它的父结点。例如,途中结点d的下一个结点是b,f的下一个结点是c。
如果一个结点既没有右子树,并且它还是父结点的右子结点,这种情形就比较复杂。我们可以沿着指向父结点的指针一直向上遍历,直到找到一个是它父结点的左子结点的结点。如果这样的结点存在,那么这个结点的父结点就是我们要找的下一个结点。例如,为了找到结点g的下一个结点,我们沿着指向父结点的指针向上遍历,先到达结点c。由于结点c是父结点a的右结点,我们继续向上遍历到达结点a。由于结点a是树的根结点。它没有父结点。因此结点g没有下一个结点。

/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
        
    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* Node)
    {
        if (Node== NULL)
            return NULL;
        TreeLinkNode* res = NULL;
        // 当前结点有右子树,那么它的下一个结点就是它的右子树中最左子结点
        if (Node->right != NULL)
        {
            TreeLinkNode* pRight = Node->right;
            while(pRight->left!=NULL)
            {
                pRight = pRight->left;
            }
            res = pRight;
        }
        // 当前结点无右子树,则需要找到一个是它父结点的左子树结点的结点
        else if (Node->next!=NULL)
        {
            // 当前结点
            TreeLinkNode* pCur = Node;
            // 父节点
            TreeLinkNode* pNext = Node->next;
            while( pNext != NULL && pNext->right == pCur)
            {
                pCur = pNext;
                pNext = pNext->next;
            }
            res = pNext;
        }
        return res;
    }
};
基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip 个人大四的毕业设计、课程设计、作业、经导师指导并认可通过的高分设计项目,评审平均分达96.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 [资源说明] 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设或者课设、作业,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96.5分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),供学习参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值