LeetCode-题目详解(四):二叉树(Tree)【遍历方式(前序、中序、后序、层序)、属性(对称、深度、平衡、路径)、修改与构造(翻转、合并)、公共祖先问题、二叉树之间的关系(相同、子树)】

在这里插入图片描述

二叉树

一、二叉树的遍历方式

144-二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

示例 1:
在这里插入图片描述

输入:root = [1,null,2,3]
输出:[1,2,3]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

示例 4:

在这里插入图片描述

输入:root = [1,2]
输出:[1,2]

示例 5:
在这里插入图片描述

输入:root = [1,null,2]
输出:[1,2]

提示:

  • 树中节点数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

进阶:递归算法很简单,你可以通过迭代算法完成吗?


递归方法:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        result = []
        def dfs(node: TreeNode):
            # 递归结束条件
            if node is None:
                return
            # 逻辑主体部分
			result.apend(node.val)
            
            # 左子树递归
            if node.left:
                dfs(node.left)
            # 右子树递归
            if node.right:
                dfs(node.right)

        dfs(root)
        return 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> result;
    vector<int> preorderTraversal(TreeNode* root) {
        if(!root){
            return {};
        }
        result.push_back(root->val);
        if(root->left){
            preorderTraversal(root->left);
        }
        if(root->right){
            preorderTraversal(root->right);
        }
        return result;
    }
};

94-二叉树的中序遍历

给定一个二叉树的根节点 root ,返回它的 中序 遍历。

示例 1:
在这里插入图片描述

输入:root = [1,null,2,3]
输出:[1,3,2]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

示例 4:
在这里插入图片描述

输入:root = [1,2]
输出:[2,1]

示例 5:
在这里插入图片描述

输入:root = [1,null,2]
输出:[1,2]

提示:

  • 树中节点数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

进阶: 递归算法很简单,你可以通过迭代算法完成吗?


/**
 * 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> result;
    vector<int> inorderTraversal(TreeNode* root) {
        dfs(root);
        return result;
    }

    void dfs(TreeNode* node){
        if(!node){
            return;
        }
        dfs(node->left);
        result.push_back(node->val);
        dfs(node->right);
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        self.result = []
        self.dfs(root)
        return self.result

    def dfs(self, node):
        # 递归结束条件
        if not node:
            return
        # 左子树递归
        self.dfs(node.left)
        self.result.append(node.val)
        # 右子树递归
        self.dfs(node.right)

145-二叉树的后序遍历

给定一个二叉树,返回它的 后序 遍历。

示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [3,2,1]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        result = []
        def dfs(node: TreeNode):
            # 递归结束条件
            if node is None:
                return
            
            # 左子树递归
            if node.left is not None:
                dfs(node.left)
            
            # 右子树递归
            if node.right is not None:
                dfs(node.right)
            
            # 逻辑主体部分
            result.apend(node.val)

        dfs(root)
        return 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> result;
    vector<int> postorderTraversal(TreeNode* root) {
        if(!root){
            return {};
        }
        if(root->left){
            postorderTraversal(root->left);
        }
        if(root->right){
            postorderTraversal(root->right);
        }
        result.push_back(root->val);

        return result;
    }
};

102-二叉树的层序遍历【剑指 Offer 32 - II. 从上到下打印二叉树 II】

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

示例:
在这里插入图片描述

二叉树:[3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层序遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

C++

/**
 * 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>> result;
        // 如果根节点是空,直接结束
        if (!root) {
            return result;
        }

        queue <TreeNode*> q;
        q.push(root);   // 先将根节点放入队列
        while (!q.empty()) {
            vector<int> curr_level;     // 存放当前层所有节点
            int curr_size = q.size();   // 当前层所有节点的总数量
            for (int i = 0; i < curr_size; ++i) {   // 循环遍历当前level的所有节点
                TreeNode* node = q.front();
                q.pop();
                curr_level.push_back(node->val);
                if (node->left){
                    q.push(node->left); // 将当前节点的左子节点放入队列
                }
                if (node->right){
                    q.push(node->right);    // 将当前节点的右子节点放入队列
                }
            }
            result.push_back(curr_level);   // 将当前层所有节点放入result     
        }

        return 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<vector<int>> levelOrder(TreeNode* root) {
        vector <vector <int>> result;
        // 如果根节点是空,直接结束
        if (!root) {
            return result;
        }
        result = bfs(root);
        return result;
    }

    vector<vector<int>> bfs(TreeNode* node){
        vector<vector<int>> result;
        queue <TreeNode*> q;
        q.push(node);   // 先将根节点放入队列
        while (!q.empty()) {
            vector<int> curr_level;     // 存放当前层所有节点
            int curr_size = q.size();   // 当前层所有节点的总数量
            for (int i = 0; i < curr_size; ++i) {   // 循环遍历当前level的所有节点
                TreeNode* node = q.front();
                q.pop();
                curr_level.push_back(node->val);
                if (node->left){
                    q.push(node->left); // 将当前节点的左子节点放入队列
                }
                if (node->right){
                    q.push(node->right);    // 将当前节点的右子节点放入队列
                }
            }
            result.push_back(curr_level);   // 将当前层所有节点放入result     
        }
        return result;
    }
};

Python

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        result = []
        # 如果根节点是空,直接结束
        if root is None:
            return result
        
        # 先将根节点放入队列
        queue = [root]

        while queue!=[]:
            arr = []    # 存放当前层所有节点
            len_queue = len(queue)  # 当前层所有节点的总数量
            for _ in range(len_queue):  # 循环遍历当前level的所有节点
                curr = queue.pop(0)
                arr.append(curr.val)
                if curr.left is not None:
                    queue.append(curr.left) # 将当前节点的左子节点放入队列
                if curr.right is not None:
                    queue.append(curr.right)    # 将当前节点的右子节点放入队列
            result.append(arr)  # 将当前层所有节点放入result  

        return result

107-二叉树的层序遍历 II

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

例如:
在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目在范围 [0, 2000] 内
  • -1000 <= Node.val <= 1000

方法:广度优先搜索

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
        result = []
        def bfs(node: TreeNode):
            # 如果根节点是空,直接结束
            if node is None:
                return
            
            queue = [node]  # 先将根节点放入队列

            while queue!=[]:	
                curr_len = len(queue)   # 当前层所有节点的总数量
                curr_level = []         # 存放当前层所有节点的val
                for _ in range(curr_len):	# 循环遍历当前level的所有节点
                    curr = queue.pop(0)
                    curr_level.apend(curr.val)
                    if curr.left is not None:
                        queue.apend(curr.left)     # 将当前节点的左子节点放入队列
                    if curr.right is not None:
                        queue.apend(curr.right)    # 将当前节点的右子节点放入队列
                
                result.insert(0, curr_level)   # 将当前层所有节点放入result 【从头部插入】   


        bfs(root)
        return result

Python

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
        result = []
        # 如果根节点是空,直接结束
        if root is None:
            return result
        
        # 先将根节点放入队列
        queue = [root]

        while queue!=[]:
            arr = []    # 存放当前层所有节点
            len_queue = len(queue)  # 当前层所有节点的总数量
            for _ in range(len_queue):  # 循环遍历当前level的所有节点
                curr = queue.pop(0)
                arr.append(curr.val)
                if curr.left is not None:
                    queue.append(curr.left) # 将当前节点的左子节点放入队列
                if curr.right is not None:
                    queue.append(curr.right)    # 将当前节点的右子节点放入队列
            result.append(arr)  # 将当前层所有节点放入result  

        return result[::-1]	# 翻转列表
/**
 * 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>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> result;
        // 如果根节点是空,直接结束
        if (!root) {
            return result;
        }

        queue<TreeNode*> q;
        q.push(root);   // 先将根节点放入队列
        while (!q.empty()) {
            vector<int> curr_level; // 存放当前层所有节点
            int curr_size  = q.size();    // 当前层所有节点的总数量
            for (int i = 0; i < curr_size ; ++i) {
                auto node = q.front();
                q.pop();
                curr_level.push_back(node->val);
                if (node->left) {
                    q.push(node->left); // 将当前节点的左子节点放入队列
                }
                if (node->right) {
                    q.push(node->right);    // 将当前节点的右子节点放入队列
                }
            }
            result.push_back(curr_level);   // 将当前层所有节点放入result   
        }
        reverse(result.begin(), result.end());  // 翻转列表
        return result;
    }
};

剑指 Offer 32 - I-从上到下打印二叉树

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回:

[3,9,20,15,7]

提示:

  • 节点总数 <= 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:
    vector<int> levelOrder(TreeNode* root) {
        vector<int> result;
        if(!root){
            return result;
        }
        queue<TreeNode*> q;
        q.push(root);
        while(q.size() != 0){
            auto curr = q.front();
            q.pop();
            result.push_back(curr->val);
            if(curr->left){
                q.push(curr->left);
            }
            if(curr->right){
                q.push(curr->right);
            }
        }
        return result;
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def levelOrder(self, root: TreeNode) -> List[int]:
        result = []
        if root is None:
            return result

        queue = [root]

        while queue!=[]:
            curr = queue.pop(0)
            result.append(curr.val)
            if curr.left is not None:
                queue.append(curr.left)
            if curr.right is not None:
                queue.append(curr.right)
        
        return result

剑指 Offer 32 - III. 从上到下打印二叉树 III

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [20,9],
  [15,7]
]

提示:

  • 节点总数 <= 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:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        if(!root){
            return result;
        }

        queue<TreeNode*> q;
        q.push(root);
        int depth = 0;
        while(!q.empty()){
            int currLen = q.size();
            vector<int> currLevel;
            for(int i = 0; i< currLen; i++){
                auto curr = q.front();
                q.pop();
                if(depth % 2 == 0){
                    currLevel.push_back(curr->val);
                }else{
                    currLevel.insert(currLevel.begin(), curr->val);
                }
                if(curr->left){
                    q.push(curr->left);
                }
                if(curr->right){
                    q.push(curr->right);
                }
            }
            result.push_back(currLevel);
            depth++;
        }

        return result;
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        result = []
        if not root:
            return result
        
        queue = [root]
        depth = 0
        while queue:
            curr_len = len(queue)
            curr_level = []
            for _ in range(curr_len):
                curr = queue.pop(0)
                if depth % 2 == 0:
                    curr_level.append(curr.val)
                else:
                    curr_level.insert(0, curr.val)
                if curr.left:
                    queue.append(curr.left)
                if curr.right:
                    queue.append(curr.right)
            result.append(curr_level)
            depth += 1

        return result

103-二叉树的锯齿形层序遍历

给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

例如:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回锯齿形层序遍历如下:

[
  [3],
  [20,9],
  [15,7]
]

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
        result = []
        
        def bfs(node: TreeNode):
            # 递归结束条件
            if node is None:
                return
            
            queue = [node]  # 首先将root压如队列中
            depth = -1
            
            while queue!=[]:
                curr_len = len(queue)   # 当前level所有节点总数量
                curr_level = []
                depth += 1  # 当前level的深度(根节点为0)
                
                for _ in range(curr_len):   # 循环遍历当前level的所有节点
                    curr = queue.pop(0)
                    if depth%2 == 0:    # 如果当前level是偶数,则当前level的元素依次从队尾加入curr_level
                        curr_level.apend(curr.val)
                    else:   # 如果当前level是奇数,则当前level的元素依次从队首加入curr_level
                        curr_level.insert(0, curr.val)
                    if curr.left is not None:
                        queue.apend(curr.left)     # 将当前节点的左子节点放入队列
                    if curr.right is not None:
                        queue.apend(curr.right)    # 将当前节点的右子节点放入队列
                
                result.apend(curr_level)   # 将当前层所有节点放入result   



        bfs(root)
        return result

199-二叉树的右视图【剑指 Offer II 046. 二叉树的右侧视图】

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:

输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

深度优先遍历:

/**
 * 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> result;
    vector<int> rightSideView(TreeNode* root) {
        dfs(root, 0);
        return result;
    }

    void dfs(TreeNode* node, int depth){
        if(!node){
            return;
        }
        if(depth == result.size()){
            result.push_back(node->val);
        }else{
            result[depth] = node->val;
        }
        dfs(node->left, depth + 1);
        dfs(node->right, depth + 1);
    }

};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def rightSideView(self, root: TreeNode) -> List[int]:
        self.result = []
        self.dfs(root, 0)
        return self.result

    def dfs(self, node, depth):
        if not node:
            return
        if depth == len(self.result):
            self.result.append(node.val)
        else:
            self.result[depth] = node.val
        self.dfs(node.left, depth + 1)
        self.dfs(node.right,depth + 1)

广度优先遍历:

/**
 * 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> result;
    vector<int> rightSideView(TreeNode* root) {
        bfs(root);
        return result;
    }

    void bfs(TreeNode* node){
        if(!node){
            return;
        }
        queue<TreeNode*> q;
        q.push(node);
        while(!q.empty()){
            int currLen = q.size();
            vector<int> currLevel;
            for(int i = 0; i < currLen; i++){
                auto curr = q.front();
                q.pop();
                currLevel.push_back(curr->val);
                if(curr->left){
                    q.push(curr->left);
                }
                if(curr->right){
                    q.push(curr->right);
                }
            }
            result.push_back(currLevel.back());
        }
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def rightSideView(self, root: TreeNode) -> List[int]:
        self.result = [] 
        self.bfs(root)
        return self.result

    def bfs(self, node):
        if node is None:
            return
        queue = [node]
        while queue!=[]:
            curr_len = len(queue)   # 当前层所有节点的总数量
            curr_level = []         # 存放当前层所有节点的val
            for _ in range(curr_len):
                curr = queue.pop(0)
                curr_level.append(curr.val)
                if curr.left is not None:
                    queue.append(curr.left)     # 将当前节点的左子节点放入队列
                if curr.right is not None:
                    queue.append(curr.right)    # 将当前节点的右子节点放入队列
            self.result.append(curr_level[-1])       # 将当前层所最右侧节点放入result  

面试题 04.03. 特定深度节点链表

给定一棵二叉树,设计一个算法,创建含有某一深度上所有节点的链表(比如,若一棵树的深度为 D,则会创建出 D 个链表)。返回一个包含所有深度的链表的数组。

示例:

输入:[1,2,3,4,5,null,7,8]

        1
       /  \ 
      2    3
     / \    \ 
    4   5    7
   /
  8

输出:[[1],[2,3],[4,5,7],[8]]

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<ListNode*> result;
    vector<ListNode*> listOfDepth(TreeNode* tree) {
        bfs(tree);
        return result;
    }

    void bfs(TreeNode* node){
        if(!node){
            return;
        }
        queue<TreeNode*> q;
        q.push(node);
        while(!q.empty()){
            int currLen = q.size();
            auto dummy = new ListNode();
            auto prev = dummy;
            for(int i = 0; i < currLen; i++){
                auto curr = q.front();
                q.pop();
                auto node = new ListNode(curr->val);
                prev->next = node;
                prev = prev->next;
                if(curr->left){
                    q.push(curr->left);
                }
                if(curr->right){
                    q.push(curr->right);
                }
            }
            result.push_back(dummy->next);
        }
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def listOfDepth(self, tree: TreeNode) -> List[ListNode]:
        self.result = []        
        self.bfs(tree)
        return self.result

    def bfs(self, node):
        if not node:
            return
        queue = [node]
        while queue:
            curr_len = len(queue)
            dummy = ListNode()
            prev = dummy
            for _ in range(curr_len):
                curr = queue.pop(0)
                node = ListNode(curr.val)
                prev.next = node
                prev = prev.next
                if curr.left:
                    queue.append(curr.left)
                if curr.right:
                    queue.append(curr.right)
            self.result.append(dummy.next)

二、二叉树的属性

剑指 Offer 28. 对称的二叉树【101-对称二叉树】

给定一个二叉树,检查它是否是镜像对称的。

示例 1:
在这里插入图片描述

输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:
在这里插入图片描述

输入:root = [1,2,2,null,3,null,3]
输出:false

提示:

  • 树中节点数目在范围 [1, 1000] 内
  • -100 <= Node.val <= 100

进阶:你可以运用递归和迭代两种方法解决这个问题吗?


递归方法:

/**
 * 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 isSymmetric(TreeNode* root) {
        if(!root){
            return false;
        }
        return dfs(root->left, root->right);
    }

    bool dfs(TreeNode* left, TreeNode* right){
        if(!left && !right){
            return true;
        }
        if(!left || !right){
            return false;
        }
        if(left->val != right->val){
            return false;
        }
        return dfs(left->left, right->right) && dfs(left->right, right->left);
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not  root:
            return False
        return self.dfs(root.left, root.right)

    def dfs(self, left, right):
        # 递归的结束条件:左右孩子都为空
        if not left and not right:
            return True
        # 递归的结束条件:左右孩子一个为空
        if not left or not right:
            return False
        # 递归的结束条件:两个值不相等
        if left.val != right.val:
            return False
        
        return self.dfs(left.left, right.right) and self.dfs(left.right, right.left)


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        def dfs(node1:TreeNode, node2:TreeNode):
            # 递归的结束条件:左右孩子都为空
            if node1 is None and node2 is None:
                return True
            # 递归的结束条件:左右孩子一个为空
            if node1 is None or node2 is None:
                return False
            # 递归的结束条件:两个值不相等
            if node1.val!=node2.val:
                return False
            
            # 递归
            out_symmetric = dfs(node1.left, node2.right)
            in_symmetric = dfs(node1.right,node2.left)

            return out_symmetric and in_symmetric

        if root is None:
            return True
        else:
            return dfs(root.left,root.right)

迭代方法-队列-层序遍历:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
# 层序遍历
class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        
        def dfs(node: TreeNode)->bool:
            if node is None:
                return True
            queue = [(node.left, node.right)]
            while queue!=[]:
                left, right = queue.pop(0)  # 使用队列-先进先出
                if left is None and right is None:
                    continue
                if left is None or right is None:
                    return False
                if left.val != right.val:
                    return False
                else:
                    queue.apend((left.left,right.right))   # 将左孩子的左孩子的左孩子、右孩子的右孩子添加入队列(对称位置)
                    queue.apend((left.right,right.left))   # 将左孩子的左孩子的右孩子、右孩子的左孩子添加入队列(对称位置)
        
            return True


        result = dfs(root)
        return result

104-二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。


递归方式一:递归函数无返回值【此时:递归终止条件也没有返回值,递归函数的调用不需要返回值,递归函数的最后也没有返回值】

/**
 * 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 result = 0;
    int maxDepth(TreeNode* root) {
        dfs(root, 1);
        return result;
    }

    void dfs(TreeNode* node, int depth){
        if(!node){
            return;
        }
        result = max(result, depth);
        dfs(node->left, depth + 1);
        dfs(node->right, depth + 1);
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    result = 0
    def maxDepth(self, root: TreeNode) -> int:
        def dfs(node:TreeNode, depth:int):
            if node is None:    # 递归终止条件:当深入到叶子节点的下一个节点(空节点)时,停止遍历
                return

            self.result = max(self.result, depth)   # 当深入到当前节点时,更新最大深度值
 
            dfs(node.left, depth + 1)   # 继续遍历左子树,深度加1
            dfs(node.right, depth + 1)  # 继续遍历右子树,深度加1

        dfs(root,1)
        return self.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:
    int result = 0;
    int maxDepth(TreeNode* root) {
        return dfs(root);
    }

    int dfs(TreeNode* node){
        if(!node){
            return 0;
        }
        int leftDepth = dfs(node->left);
        int rightDepth = dfs(node->right);
        int result = max(leftDepth, rightDepth) + 1;
        return result;
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
# 经典后序遍历
class Solution:
    def maxDepth(self, root: TreeNode) -> int:

        def dfs(node:TreeNode)->int:
            if node is None:    # 递归终止条件:当深入到叶子节点的下一个节点(空节点)时,停止遍历,并且返回0
                return 0

            leftDepth = dfs(node.left)    # 递归计算当前节点左子树的深度
            rightDepth = dfs(node.right)  # 递归计算当前节点右子树的深度
 			
 			# 主体逻辑
            result =  max(leftDepth,rightDepth) + 1 # 计算以当前节点为根的树,其最大深度
 
            return result  # 将当前节点的深度返回给上一层,用于累加
        
        max_depth = dfs(root)
        return max_depth

层次遍历:

# Definition for a binary tree node.
# class TreeNode:#     def __init__(self, val=0, left=None, right=None)-
#         self.val = val
#         self.left = left
#         self.right = right
class Solution-
    def maxDepth(self, root- TreeNode) -> int-
        max_depth = 0

        if root is None-
            return max_depth

        queue = []  # 初始化队列
        queue.apend(root) # 将根节点加入队列

        while queue!=[]-    # 如果队列不为空(还有元素没被弹出)
            curr_level_len = len(queue) # 队列中元素数量(每一次while循环初始时,queue中元素中数量为树的当前level的节点中数量)
            for _ in range(curr_level_len)- # 遍历队列中的所有元素(即:树的当前层的所有节点)
                curr = queue.pop(0) # 弹出队首元素
                if curr.left is not None-   # 如果弹出的队首元素有左节点,则向队尾添加该左节点
                    queue.apend(curr.left)
                if curr.right is not None-  # 如果弹出的队首元素有右节点,则向队尾添加该右节点
                    queue.apend(curr.right)
            max_depth += 1 # 遍历完树的当前level的所有节点后,将当前层数加入到max_depth,然后遍历树的下一个level的所有节点

        return max_depth      

110-平衡二叉树【剑指 Offer 55 - II. 平衡二叉树】

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

本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

示例 1:
在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:true

示例 2:
在这里插入图片描述

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

示例 3:

输入:root = []
输出:true

提示:

  • 树中的节点数在范围 [ 0 , 5000 ] [0, 5000] [0,5000]
  • − 1 0 4 < = N o d e . v a l < = 1 0 4 -10^4 <= Node.val <= 10^4 104<=Node.val<=104

/**
 * 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 result = true;
    bool isBalanced(TreeNode* root) {
        dfs(root);
        return result;
    }

    int dfs(TreeNode* node){
        if(!node){
            return 0;
        }
        int leftDepth = dfs(node->left);
        int rightDepth = dfs(node->right);

        if(abs(rightDepth - leftDepth) > 1){
            result = false;
        }

        return max(leftDepth, rightDepth) + 1;
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    
    is_balanced = True

    def isBalanced(self, root: TreeNode) -> bool:
        
        def dfs(node: TreeNode)->int:
            if node is None:    # 递归终止条件:当深入到叶子节点的下一个节点(空节点)时,停止遍历,并且返回 depth = 0
                return 0

            left_depth = dfs(node.left)     # 递归计算当前节点左子树的深度
            right_depth = dfs(node.right)   # 递归计算当前节点右子树的深度

            # 主体逻辑部分
            if abs(right_depth - left_depth) > 1:   
                self.is_balanced = False

            return max(left_depth, right_depth) + 1     # 将当前节点的深度返回给上一层,用于累加

        dfs(root)

        return self.is_balanced

111-二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。

示例 1:
在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:

输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

提示:

  • 树中节点数的范围在 [ 0 , 1 0 5 ] [0, 10^5] [0,105]
  • -1000 <= Node.val <= 1000

递归方式:递归函数有返回值【此时:递归终止条件必须有返回值,递归函数的调用后也要有返回值,递归函数最后必须要有返回值】

/**
 * 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 minDepth(TreeNode* root) {
        if(!root){
            return 0;
        }
        int left = minDepth(root->left);
        int right = minDepth(root->right);

        if(left == 0){          // 如果左孩子为空,则left ==0, 直接返回 right + 1
            return right + 1;
        }else if(right == 0){   // 如果右孩子为空,right == 0, 直接返回 left + 1
            return left + 1;
        }else{                  // 如果左右孩子都不为空,则返回较小深度 + 1
            return min(left, right) + 1;
        }
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0

        left = self.minDepth(root.left)
        right = self.minDepth(root.right)

        if left == 0:       # 如果左孩子为空,则left ==0, 直接返回 right + 1
            return right + 1
        elif right == 0:    # 如果右孩子为空,right == 0, 直接返回 left + 1
            return left + 1;  
        else:               # 如果左右孩子都不为空,则返回较小深度 + 1
            return min(left, right) + 1

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def minDepth(self, root: TreeNode) -> int:
        def dfs(node):
            if not node:
                return 0

            left = dfs(node.left)
            right = dfs(node.right)

            if left == 0:       # 如果左孩子为空,则left ==0, 直接返回 right + 1
                return right + 1
            elif right == 0:    # 如果右孩子为空,right == 0, 直接返回 left + 1
                return left + 1;  
            else:               # 如果左右孩子都不为空,则返回较小深度 + 1
                return min(left, right) + 1
       
        return dfs(root)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def minDepth(self, root: TreeNode) -> int:
        def dfs(node:TreeNode)->int:
            if node is None:
                return 0

            # 到达叶子节点
            if node.left is None and node.right is None:
                return 1
            
            # 左子树不为空 & 右子树为空
            if node.left is not None and node.right is None:
                return dfs(node.left) + 1

            # 左子树为空 & 右子树不为空
            if node.left is None and node.right is not None:
                return dfs(node.right) + 1
             
            # 左右子树均不为空
            return min(dfs(node.left) + 1,  dfs(node.right) + 1)
        
        return dfs(root)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def minDepth(self, root: TreeNode) -> int:
        def dfs(node):
            if not node:
                return 0

            left = dfs(node.left)
            right = dfs(node.right)

            if not left or not right:   # 如果左孩子为空,则left ==0, 直接返回 right + 1, 如果右孩子为空,right == 0, 直接返回 left + 1
                return left + right + 1  
            else:                       # 如果左右孩子都不为空,则返回较小深度 + 1
                return min(left, right) + 1
       
        return dfs(root)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def minDepth(self, root: TreeNode) -> int:
        def dfs(node):
            if not node.left and not node.right:
                return 1
            left = dfs(node.left) if node.left else float('inf')
            right = dfs(node.right) if node.right else float('inf')
            return min(left, right) + 1
        
        if not root:
            return 0
        return dfs(root)

迭代方法:层序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
# 层序遍历(迭代)
class Solution:
    depth = 0
    def minDepth(self, root: TreeNode) -> int:
        def bfs(node:TreeNode)->int:
            queue = [node]
            while queue!=[]:
                curr_level_lens = len(queue)
                self.depth +=1
                for _ in range(curr_level_lens):
                    curr = queue.pop(0)
                    if curr.left is None and curr.right is None:
                        return
                    if curr.left is not None:
                        queue.apend(curr.left)
                    if curr.right is not None:
                        queue.apend(curr.right)


        if root is None:
            return 0
        bfs(root)
        return self.depth

三、二叉树路径

1、自顶向下

这类题通常用深度优先搜索(DFS)和广度优先搜索(BFS)解决,BFS较DFS繁琐。

DFS模板:

一般路径:
vector<vector<int>>res;
void dfs(TreeNode*root,vector<int>path){
    if(!root){
    	return;  //根节点为空直接返回
    }
    path.push_back(root->val);  //作出选择
    if(!root->left && !root->right){ //如果到叶节点  
        res.push_back(path);
        return;
    }
    dfs(root->left,path);  //继续递归
    dfs(root->right,path);
}

# **给定和的路径:**
void dfs(TreeNode*root, int sum, vector<int> path){
    if (!root)
        return;
    sum -= root->val;
    path.push_back(root->val);
    if (!root->left && !root->right && sum == 0){
        res.push_back(path);
        return;
    }
    dfs(root->left, sum, path);
    dfs(root->right, sum, path);
}

这类题型DFS注意点:

  1. 如果是找路径和等于给定target的路径的,那么可以不用新增一个临时变量cursum来判断当前路径和,
    只需要用给定和target减去节点值,最终结束条件判断target==0即可

  2. 是否要回溯:二叉树的问题大部分是不需要回溯的,原因如下:
    二叉树的递归部分:dfs(root->left),dfs(root->right)已经把可能的路径穷尽了,
    因此到任意叶节点的路径只可能有一条,绝对不可能出现另外的路径也到这个满足条件的叶节点的;
    而对比二维数组(例如迷宫问题)的DFS,for循环向四个方向查找每次只能朝向一个方向,并没有穷尽路径,
    因此某一个满足条件的点可能是有多条路径到该点的
    并且visited数组标记已经走过的路径是会受到另外路径是否访问的影响,这时候必须回溯

  3. 找到路径后是否要return:
    取决于题目是否要求找到叶节点满足条件的路径,如果必须到叶节点,那么就要return;
    但如果是到任意节点都可以,那么必不能return,因为这条路径下面还可能有更深的路径满足条件,还要在此基础上继续递归

  4. 是否要双重递归(即调用根节点的dfs函数后,继续调用根左右节点的pathsum函数):看题目要不要求从根节点开始的,还是从任意节点开始

112-路径总和(判断路径和是否等于一个数)

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。

叶子节点 是指没有子节点的节点。

示例 1:

在这里插入图片描述

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true

示例 2:
在这里插入图片描述

输入:root = [1,2,3], targetSum = 5
输出:false

示例 3:

输入:root = [1,2], targetSum = 0
输出:false

提示:

  • 树中节点的数目在范围 [0, 5000] 内
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum: <= 1000

备注:当题目中提到了叶子节点时,正确的做法一定要同时判断节点的左右子树同时为空才是叶子节点。

递归方式一:递归函数无返回值

此时:递归终止条件也没有返回值,递归函数的调用不需要返回值,递归函数的最后也没有返回值

# Definition for a binary tree node.
# class TreeNode-
#     def __init__(self, val=0, left=None, right=None):#         self.val = val
#         self.left = left
#         self.right = right
class Solution-
    isSum = False
    def hasPathSum(self, root- TreeNode, targetSum- int) -> bool-
        def dfs(node-TreeNode, path- int)-
            
            # 递归终止条件:当深入到叶子节点的下一个节点(空节点)时,停止遍历
            if node is None-
                return
            
            # 主体逻辑部分:到达叶子节点,统计路径和是否与targetSum相同
            if node.left is None and node.right is None-
                path += node.val
                if path == targetSum-
                    self.isSum = True
            
            # 递归
            if node.left is not None:
                dfs(node.left, path + node.val)
            if node.right is not None:
                dfs(node.right, path + node.val)

        dfs(root, 0)
        return self.isSum

递归方式二:递归函数有返回值

此时:递归终止条件必须有返回值,递归函数的调用后也要有返回值,递归函数最后必须要有返回值

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
        def dfs(node:TreeNode, sum:int)->bool:
            # 递归终止条件
            if node is None:
                return False
            
            sum = sum - node.val
            
            # 逻辑主体部分
            if node.left is None and node.right is None:
            	if sum == 0:
                	return True     # 当到达叶子节点时,剩余的sum==0,说明该路径所有节点的和正好为targetSum

            # 递归
            left_flag = False
            right_flag = False

            if node.left is not None:
                left_flag = dfs(node.left, sum)      # 从targetSum中减去当前节点的val后,再传给子节点
            if node.right is not None:
                right_flag = dfs(node.right, sum)    # 从targetSum中减去当前节点的val后,再传给子节点
            
            return left_flag or right_flag

        result = dfs(root, targetSum)

        return result
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
        def dfs(node:TreeNode, sum:int)->bool:
            # 递归终止条件
            if node is None:
                return False
            sum = sum - node.val
            # 逻辑主体部分
            if node.left is None and node.right is None and sum == 0:
                return True     # 当到达叶子节点时,剩余的sum==0,说明该路径所有节点的和正好为targetSum
            # 递归
            return dfs(node.left, sum) or dfs(node.right, sum)

        result = dfs(root, targetSum)
        return 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:
    bool hasPathSum(TreeNode* root, int targetSum) {
        return dfs(root, targetSum);
    }

    bool dfs(TreeNode* node, int sum){
        if(!node){
            return false;
        }
        sum = sum - node->val;
        if(!node->left && !node->right && sum == 0){
            return true;
        }
        return dfs(node->left, sum) or dfs(node->right, sum);
    }
};
/**
 * 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 hasPathSum(TreeNode* root, int targetSum) {
        return dfs(root, targetSum);
    }

    bool dfs(TreeNode* node, int sum){
        if(node == nullptr){
            return false;
        }
        sum = sum - node->val;
        if(node->left == nullptr && node->right == nullptr && sum == 0){
            return true;
        }
        return dfs(node->left, sum) or dfs(node->right, sum);
    }
};

113-路径总和 II【剑指 Offer 34. 二叉树中和为某一值的路径】

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

示例 1:

在这里插入图片描述

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2:
在这里插入图片描述

输入:root = [1,2,3], targetSum = 5
输出:[]

示例 3:

输入:root = [1,2], targetSum = 0
输出:[]

提示:

  • 树中节点总数在范围 [0, 5000] 内
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

/**
 * 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>> result;

    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<int> path;
        dfs(root, targetSum, path);
        return result;
    }

    // vector<int> path:值传递;vector<int>& path:引用传递
    void dfs(TreeNode* node, int targetSum, vector<int> path){
        if(!node){
            return;
        }
        path.push_back(node->val);
        targetSum -= node->val;
        if(!node->left && !node->right && targetSum == 0){
            result.push_back(path);
            return;
        }
        dfs(node->left, targetSum, path);
        dfs(node->right, targetSum, path);
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        self.result = []
        
        self.dfs(root, targetSum, [])
        return self.result

    def dfs(self, node, target, path):
        if not node:
            return
        target = target - node.val
        path = path + [node.val]
        if not node.left and not node.right and target == 0:
            self.result.append(path)
        self.dfs(node.left, target, path)
        self.dfs(node.right, target, path)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
        paths = []
        def dfs(node:TreeNode,path,sum):
            # 递归终止条件
            if node is None:    
                return
            # 逻辑主体部分:叶子节点
            if node.left is None and node.right is None:
                sum -= node.val
                curr_path = path + [node.val]
                if sum == 0:
                    paths.apend(curr_path)
            
            # 递归
            if node.left is not None:
                dfs(node.left,path+[node.val],sum-node.val)
            if node.right is not None:
                dfs(node.right, path+[node.val],sum-node.val)

        dfs(root,[],targetSum)
        return paths

437-路径总和 III

给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

返回 3。和等于 8 的路径有-

1.  5 -> 3
2.  5 -> 2 -> 1
3.  -3 -> 11

双递归:内外两层递归实现暴力遍历所有节点
所谓双递归,其实就是内外两层递归实现暴力遍历所有节点
外层递归保证遍历到树的所有节点;内层递归才是真正寻找当前节点的递归 – 以当前节点为根节点,路径和符合要求的情况
然后将所有情况加在一起就是最终的结果了。
时间复杂度分析:外层递归遍历所有节点,内层节点遍历子树节点,所以最终是 1+2+3+…+N,所以平均 O ( N 2 ) O(N^2) O(N2)
空间复杂度:O(1)

/**
 * 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) {}
 * };
 */
/*
双递归:
所谓双递归,其实就是内外两层递归实现暴力遍历所有节点
外层递归保证遍历到树的所有节点;内层递归才是真正寻找当前节点的递归 -- 以当前节点为根节点,路径和符合要求的情况
然后将所有情况加在一起就是最终的结果了。
时间复杂度分析:外层递归遍历所有节点,内层节点遍历子树节点,所以最终是 1+2+3+...+N,所以平均O(N^2)
空间复杂度:O(1)
*/
class Solution {
public:
    int result = 0;
    int pathSum(TreeNode* root, int targetSum) {
        dfs(root, targetSum);
        return result;

    }
    void dfs(TreeNode* node, long sum){
        // 递归终止条件
        if(!node){
            return;
        }
        count(node, sum);       // 统计以当前节点为起始点的路径
        dfs(node->left, sum);   // 统计以当前节点的左节点为起始点的路径
        dfs(node->right, sum);  // 统计以当前节点的右节点为起始点的路径
    }
    
    // 统计以当前节点为起始点的路径是否有和为targetSum的路径
    void count(TreeNode* node, long sum){
        if(!node){
            return;
        }
        sum = sum - node->val;
        if(sum == 0){
            result++;
        }
        count(node->left, sum);
        count(node->right, sum);
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
'''
双递归:
所谓双递归,其实就是内外两层递归实现暴力遍历所有节点
外层递归保证遍历到树的所有节点;内层递归才是真正寻找当前节点的递归 -- 以当前节点为根节点,路径和符合要求的情况
然后将所有情况加在一起就是最终的结果了。
时间复杂度分析:外层递归遍历所有节点,内层节点遍历子树节点,所以最终是 1+2+3+...+N,所以平均O(N^2)
空间复杂度:O(1)
'''

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        self.result = 0
        self.dfs(root, targetSum)
        return self.result

    def dfs(self, node, sum):
        # 递归终止条件
        if node is None:
            return
        # 统计以当前节点为起始点的路径
        self.count(node, sum)
        # 统计以当前节点的左节点为起始点的路径
        self.dfs(node.left, sum)
        # 统计以当前节点的右节点为起始点的路径
        self.dfs(node.right, sum)

    # 统计以当前节点为起始点的路径是否有和为targetSum的路径
    def count(self, node, sum):
        if node is None:
            return
        sum = sum - node.val
        if sum == 0:
            self.result += 1
        self.count(node.left, sum)
        self.count(node.right,sum)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
'''
双递归:
所谓双递归,其实就是内外两层递归实现暴力遍历所有节点
外层递归保证遍历到树的所有节点;内层递归才是真正寻找当前节点的递归 -- 以当前节点为根节点,路径和符合要求的情况
然后将所有情况加在一起就是最终的结果了。
时间复杂度分析:外层递归遍历所有节点,内层节点遍历子树节点,所以最终是 1+2+3+...+N,所以平均O(N^2)
空间复杂度:O(1)
'''

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        self.result = 0
        # 统计以当前节点为起始点的路径是否有和为targetSum的路径
        def count(node:TreeNode,sum):
            if node is None:
                return
            sum = sum - node.val
            if sum == 0:
                self.result += 1
            count(node.left, sum)
            count(node.right,sum)

        def dfs(node:TreeNode, sum:int):
            # 递归终止条件
            if node is None:
                return
            # 统计以当前节点为起始点的路径
            count(node, sum)
            # 统计以当前节点的左节点为起始点的路径
            dfs(node.left, sum)
            # 统计以当前节点的右节点为起始点的路径
            dfs(node.right, sum)
            
        dfs(root, targetSum)

        return self.result

面试题 04.12. 求和路径

988. 从叶结点开始的最小字符串

2、非自顶向下【就是从任意节点到任意节点的路径,不需要自顶向下】

这类题目一般解题思路如下:
设计一个辅助函数maxpath,调用自身求出以一个节点为根节点的左侧最长路径left和右侧最长路径right,那么经过该节点的最长路径就是left+right
接着只需要从根节点开始dfs,不断比较更新全局变量即可

int res=0;
int maxPath(TreeNode *root) //以root为路径起始点的最长路径
{
    if (!root)
        return 0;
    int left=maxPath(root->left);
    int right=maxPath(root->right);
    res = max(res, left + right + root->val); //更新全局变量  
    return max(left, right);   //返回左右路径较长者
}

这类题型DFS注意点:

  1. left,right代表的含义要根据题目所求设置,比如最长路径、最大路径和等等
  2. 全局变量res的初值设置是0还是INT_MIN要看题目节点是否存在负值,如果存在就用INT_MIN,否则就是0
  3. 注意两点之间路径为1,因此一个点是不能构成路径的

124-二叉树中的最大路径和

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

示例 1:
在这里插入图片描述

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:
在这里插入图片描述

输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

提示:

  • 树中节点数目范围是 [ 1 , 3 ∗ 1 0 4 ] [1, 3 * 10^4] [1,3104]
  • -1000 <= Node.val <= 1000

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

# 二叉树的递归遍历,只要包含如下代码,就可以了,
# 而针对不同的题目,我们会设置一些递归的返回值(包括终止条件),设计递归函数的参数,或者用外部变量记录的方式,来达到题目的要求。
'''
def dfs(root):
    if not root: 
        return
    dfs(root.left)
    dfs(root.right)
'''
# 而返回值、参数、外部变量是不影响递归的进行的(只要有以上代码),这时候就是发挥人类智慧,开始设计递归的时候。
# 至少对于二叉树的递归,每个题目都可以这么想。

# 本题最重要的就是返回值的设计,鉴于最开始的分析,其实返回值有和没有并不影响递归遍历节点,
# 但是本题必须要借用返回值来在每一层递归中比较路径的大小,因为如果不将这个路径的大小随着函数返回的话,外部变量ans将会无法每一轮比较和更新。

 

class Solution:
    ans = float('-inf')

    def maxPathSum(self, root: TreeNode) -> int:
        
        def dfs(node):
            if not node: 
                return 0

            sum_left = dfs(node.left)   # 左子树和
            sum_right = dfs(node.right) # 右子树和

            self.ans = max(self.ans, max(sum_left,0) + max(sum_right, 0) + node.val)    # 左、根、右子树相加和最大值
            
            return max(max(sum_left, sum_right) + node.val , 0)  # return max(sum_left, sum_right, 0) + node.val
        
        dfs(root)
        
        return self.ans

687-最长同值路径

给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。

注意:两个节点之间的路径长度由它们之间的边数表示。

示例 1:

输入:

          5
         / \
        4   5
       / \   \
      1   1   5

输出:

2

示例 2:

输入:

          1
         / \
        4   5
       / \   \
      4   4   5

输出:

2

注意: 给定的二叉树不超过10000个结点。 树的高度不超过1000。


/**
 * 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 result = 0;
    int longestUnivaluePath(TreeNode* root) {
        dfs(root);
        return result;
    }

    int dfs(TreeNode* node){
        if(!node){
            return 0;
        }
        int left = dfs(node->left); // 左子树最长同值路径长度
        int right = dfs(node->right);   // 右子树最长同值路径长度

        int leftTemp = 0;
        int rightTemp = 0;

        // 本节点与左子树构成的最长同值路径长度
        if(node->left && node->left->val == node->val){
            leftTemp = left + 1;
        }
        // 本节点与右子树构成的最长同值路径长度
        if(node->right && node->right->val == node->val){
            rightTemp = right + 1;
        }

        // 更新全局最长同值路径长度
        result = max(result, leftTemp + rightTemp);

        return max(leftTemp, rightTemp);    // 返回当前节点的最长同值路径长度

    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def longestUnivaluePath(self, root: Optional[TreeNode]) -> int:
        self.result = 0
        def dfs(root):
            if root is None:
                return 0 
            
            left = dfs(root.left)       # 左子树最长同值路径长度
            right = dfs(root.right)     # 右子树最长同值路径长度

            left_temp = 0
            right_temp = 0

            # 本节点与左子树构成的最长同值路径长度
            if root.left is not None and root.left.val == root.val:
                left_temp = left + 1

            # 本节点与右子树构成的最长同值路径长度
            if root.right is not None and root.right.val == root.val:
                right_temp = right + 1


            self.result = max(self.result, left_temp + right_temp)    # 更新全局最长同值路径长度
            

            return max(left_temp, right_temp)   # 返回当前节点的最长同值路径长度

        dfs(root)
        return self.result

543-二叉树的直径(两节点的最长路径)

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

示例 :

给定二叉树

          1
         / \
        2   3
       / \     
      4   5    

返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

注意:两结点之间的路径长度是以它们之间边的数目表示。


/**
 * 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 result = 0;
    int diameterOfBinaryTree(TreeNode* root) {
        dfs(root);
        return result;
    }

    int dfs(TreeNode* node){
        if(!node){
            return 0;
        }
        // 主体逻辑
        int leftDepth = dfs(node->left);
        int rightDepth = dfs(node->right);
        result = max(result, leftDepth + rightDepth);   // 当前节点最大直径 = 当前节点左右子树最大深度的和
        return max(leftDepth, rightDepth) + 1;  // 返回当前节点的最大深度
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        self.result = 0
        self.dfs(root)
        return self.result

    def dfs(self, node):
        if not node:
            return 0
        # 主体逻辑
        left_depth = self.dfs(node.left)
        right_depth = self.dfs(node.right)
        self.result = max(self.result, left_depth + right_depth)  # 当前节点最大直径 = 当前节点左右子树最大深度的和

        return max(left_depth , right_depth) + 1    # 返回当前节点的最大深度
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:

    max_diameter = 0
    
    def diameterOfBinaryTree(self, root: TreeNode) -> int:

        def dfs(node:TreeNode)->int:
            if node is None:
                return 0
            
            left_max_depth = dfs(node.left)
            right_max_depth = dfs(node.right)
            
            # 主体逻辑
            max_depth = left_max_depth + right_max_depth        # 当前节点最大直径 = 当前节点左右子树最大深度的和
            self.max_diameter = max(self.max_diameter, max_depth)   # 更新整棵树的最大直径
            
            return max(left_max_depth, right_max_depth) + 1     # 返回当前节点的最大深度

        dfs(root)

        return self.max_diameter

257-二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

说明: 叶子节点是指没有子节点的节点。

示例:
在这里插入图片描述

输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3

示例 2:

输入:root = [1]
输出:["1"]

提示:

  • 树中节点的数目在范围 [1, 100] 内
  • -100 <= Node.val <= 100

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        result = []
        
        if root is None:
            return result

        def bfs(node:TreeNode, path:str):
            # 递归结束条件
            if node is None:
                return
            
            # 如果当前节点是叶节点,则将已得到的路径加入最终结果
            if node.left is None and node.right is None: 
                path = path + str(node.val)
                result.apend(path)
            # 当前节点不是叶节点,则继续遍历,分别对左右子节点递归调用自身。
            else:   
                path = path + str(node.val) + "->"
            
            if node.left is not None:
            	bfs(node.left, path)
            if node.right is not None:
            	bfs(node.right, path)

        bfs(root, path = "")
        return 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<string> result;
    
    vector<string> binaryTreePaths(TreeNode* root) {
        dfs(root, "");
        return result;
    }

    void dfs(TreeNode* node, string path){
        if(node == nullptr){
            return;
        }
        if(node->left == nullptr && node->right == nullptr){
            path = path + to_string(node->val);
            result.push_back(path);
        }else{
            path = path + to_string(node->val) + "->";
        }
        dfs(node->left, path);
        dfs(node->right, path);
    }
};

222-完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

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

示例 1:
在这里插入图片描述

输入:root = [1,2,3,4,5,6]
输出:6

示例 2:

输入:root = []
输出:0

示例 3:

输入:root = [1]
输出:1

提示:

  • 树中节点的数目范围是[0, 5 * 104]
  • 0 <= Node.val <= 5 * 104
  • 题目数据保证输入的树是 完全二叉树

进阶:遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?


递归:不使用中间变量

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countNodes(self, root: TreeNode) -> int:

        def dfs(node):
            if not node:
                return 0
            return dfs(node.left) + dfs(node.right) + 1
        
        return dfs(root)
/**
 * 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 countNodes(TreeNode* root) {
        return dfs(root);
    }
    int dfs(TreeNode* node){
        if(!node){
            return 0;
        }
        return dfs(node->left) + dfs(node->right) + 1;
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        def dfs(node):
            if node is None:
                return 0
            
            left = 0
            right = 0

            if node.left is not None:
                left = dfs(node.left)
            if node.right is not None:
                right = dfs(node.right)

            return left + right + 1

        return dfs(root)

递归:使用中间变量

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        result = 0
        
        def dfs(node):
            nonlocal result
            if not node:
                return
            
            result += 1
            
            dfs(node.left)
            dfs(node.right)

        dfs(root)

        return 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:
    int result = 0;
    int countNodes(TreeNode* root) {
        dfs(root);
        return result;
    }
    void dfs(TreeNode* node){
        if(!node){
            return;
        }
        result++;
        dfs(node->left);
        dfs(node->right);
    }
};

层序遍历:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        result = 0
        if root is None:
            return result

        queue = [root]

        while queue!=[]:
            curr_level = []
            for _ in range(len(queue)):
                temp = queue.pop(0)
                curr_level.apend(temp)
                if temp.left is not None:
                    queue.apend(temp.left)
                if temp.right is not None:
                    queue.apend(temp.right)
            result +=len(curr_level)

        return 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:
    int result = 0;
    int countNodes(TreeNode* root) {
        if(!root){
            return result;
        }
        queue<TreeNode*> q;
        q.push(root);
        while(q.size() != 0){
            vector<TreeNode*> v;
            for(int i = 0; i < q.size(); i++){
                auto temp = q.front();
                q.pop();
                v.push_back(temp);
                if(temp->left){
                    q.push(temp->left);
                }
                if(temp->right){
                    q.push(temp->right);
                }
            }
            result += v.size();
        }
        return result;
    }
};

404-左叶子之和

计算给定二叉树的所有左叶子之和。

示例 1:
在这里插入图片描述

输入: root = [3,9,20,null,null,15,7] 
输出: 24 
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

示例 2:

输入: root = [1]
输出: 0

提示:

  • 节点数在 [1, 1000] 范围内
  • -1000 <= Node.val <= 1000

DFS-递归方法:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    result = 0
    def sumOfLeftLeaves(self, root: TreeNode) -> int:
        def dfs(node: TreeNode):
            if node is None:
                return
            if node.left is not None and node.left.left is None and node.left.right is None:
                self.result += node.left.val
            if node.left is not None:
                dfs(node.left)
            if node.right is not None:
                dfs(node.right)


        dfs(root)
        return self.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:
    int result = 0;
    int sumOfLeftLeaves(TreeNode* root) {
        dfs(root);
        return result;
    }
    void dfs(TreeNode* node){
        if(!node){
            return;
        }
        if(node->left && !node->left->left && !node->left->right){
            result += node->left->val;
        }
        if(node->left){
            dfs(node->left);
        }
        if(node->right){
            dfs(node->right);
        }
    }
};

BFS-迭代方法(层序遍历):

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    result = 0
    def sumOfLeftLeaves(self, root: TreeNode) -> int:
        def bfs(node: TreeNode)->int:
            if node is None:
                return
            queue = [node]
            while queue!=[]:
                curr = queue.pop(0)
                if curr.left is not None and curr.left.left is None and curr.left.right is None:
                    self.result += curr.left.val
                if curr.left is not None:
                    queue.apend(curr.left)
                if curr.right is not None:
                    queue.apend(curr.right)
                

        bfs(root)
        return self.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:
    int result = 0;
    int sumOfLeftLeaves(TreeNode* root) {
        bfs(root);
        return result;
    }

    void bfs(TreeNode* node){
        if(!node){
            return;
        }
        queue<TreeNode*> q;
        q.push(node);
        while(!q.empty()){
            auto curr = q.front();
            q.pop();
            if(curr->left && !curr->left->left && !curr->left->right){
                result += curr->left->val;
            }
            if(curr->left){
                q.push(curr->left);
            }
            if(curr->right){
                q.push(curr->right);
            }
        }
    }
};

513-找树左下角的值

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

示例 1:
在这里插入图片描述

输入: root = [2,1,3]
输出: 1

示例 2:
在这里插入图片描述

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7

提示:

  • 二叉树的节点个数的范围是 [ 1 , 1 0 4 ] [1,10^4] [1,104]
  • − 2 31 < = N o d e . v a l < = 2 31 − 1 -2^{31} <= Node.val <= 2^{31} - 1 231<=Node.val<=2311

深度优先遍历

/**
 * 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> result;
    int findBottomLeftValue(TreeNode* root) {
        dfs(root, 0);
        return result.back();

    }

    void dfs(TreeNode* node, int depth){
        if(!node){
            return;
        }
        if(depth == result.size()){
            result.push_back(node->val);
        }
        dfs(node->left, depth + 1);
        dfs(node->right, depth + 1);
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        result = []
        def dfs(node, depth):
            if not node:
                return
            # 只有当进入新的一层时,才加入最左侧的节点
            if depth == len(result):
                result.append(node.val)
            dfs(node.left, depth + 1)
            dfs(node.right, depth + 1)
        
        dfs(root, 0)
        return result[-1]

层序遍历方法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def findBottomLeftValue(self, root: TreeNode) -> int:
        result = []
        def bfs(node):
            if node is None:
                return
            queue = [node]
            while queue!=[]:
                curr_len = len(queue)
                curr_level = []
                for _ in range(curr_len):
                    curr = queue.pop(0)
                    curr_level.apend(curr.val)
                    if curr.left is not None:
                        queue.apend(curr.left)
                    if curr.right is not None:
                        queue.apend(curr.right)
            result.apend(curr_level)

        bfs(root)
        return result[-1][0]

四、二叉树的修改与构造

复制二叉树

# Definition for a binary tree node.
from typing import List


class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


# 从前序与中序遍历序列构造二叉树
def buildTreeFromInAndPre(preorder: List[int], inorder: List[int]) -> TreeNode:
    if len(preorder) == 0:
        return None
    root_val = preorder[0]
    root_idx = inorder.index(root_val)
    root = TreeNode(root_val)
    root.left = buildTreeFromInAndPre(preorder[1:root_idx + 1], inorder[0:root_idx])
    root.right = buildTreeFromInAndPre(preorder[root_idx + 1:], inorder[root_idx + 1:])

    return root


# 从后序与中序遍历序列构造二叉树
def buildTreeFromInAndPost(inorder: List[int], postorder: List[int]) -> TreeNode:
    if len(inorder) == 0:
        return None
    root_val = postorder[-1]
    root_idx = inorder.index(root_val)
    root = TreeNode(root_val)
    root.left = buildTreeFromInAndPost(inorder[0: root_idx], postorder[0: root_idx])
    root.right = buildTreeFromInAndPost(inorder[root_idx + 1:], postorder[root_idx:-1])

    return root

# 前序遍历
def preorderTraversal(root: TreeNode) -> List[int]:
    result = []

    def dfs(node):
        if not node:
            return
        result.append(node.val)
        dfs(node.left)
        dfs(node.right)

    dfs(root)
    return result

# 中序遍历
def inorderTraversal(root: TreeNode) -> List[int]:
    result = []

    def dfs(node):
        if not node:
            return
        dfs(node.left)
        result.append(node.val)
        dfs(node.right)

    dfs(root)
    return result

# 后序遍历
def postorderTraversal(root: TreeNode) -> List[int]:
    result = []

    def dfs(node):
        if not node:
            return
        dfs(node.left)
        dfs(node.right)
        result.append(node.val)

    dfs(root)
    return result

# 复制二叉树
def copyTree(root: TreeNode) -> TreeNode:
    def dfs(node):
        if not node:
            return None
        copy = TreeNode(node.val)
        copy.left = dfs(node.left)
        copy.right = dfs(node.right)
        return copy

    return dfs(root)


preorder = [3, 9, 20, 15, 7]
inorder = [9, 3, 15, 20, 7]
postorder = [9, 15, 7, 20, 3]
root = buildTreeFromInAndPre(preorder, inorder)
newroot = copyTree(root)
result = inorderTraversal(newroot)
print('result = ', result)

打印结果:

result =  [9, 3, 15, 20, 7]

105-从前序与中序遍历序列构造二叉树 【剑指 Offer 07-重建二叉树】

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

根据一棵树的前序遍历与中序遍历构造二叉树。

注意:你可以假设树中没有重复的元素。

示例 1:
在这里插入图片描述

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder 和 inorder 均 无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

方法一:递归【O(n),其中 n 是树中的节点个数】

在这里插入图片描述

/**
 * 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* buildTree(vector<int>& preorder, vector<int>& inorder) {
        // 递归结束条件
        if (!preorder.size()) {
            return nullptr;
        }
        int rootVal = preorder[0];
        int rootIdx = find(inorder.begin(), inorder.end(), rootVal) - inorder.begin();  // 查找vector元素下标
        std::cout << "rootIdx = " << rootIdx << std::endl;
        TreeNode* root = new TreeNode(rootVal);
 
        // 前序遍历中,索引rootIdx前的节点为根+左子树,preorder[1: rootIdx + 1]为左子树数组
        // 中序遍历中,索引rootIdx为根节点,inorder[0: rootIdx]为左子树数组
        vector<int> preorderLeft(preorder.begin() + 1, preorder.begin() + rootIdx + 1); // vector切片【初始化截取】
        vector<int> inorderLeft(inorder.begin(), inorder.begin() + rootIdx);  // vector切片【初始化截取】
        root->left = buildTree(preorderLeft, inorderLeft);
 
        // 索引rootIdx后的节点为右子树所有节点,preorder[rootIdx + 1:]为右子树数组
        // 中序遍历中,索引rootIdx为根节点,inorder[rootIdx + 1: ]为右子树数组
        vector<int> preorderRight(preorder.begin() + rootIdx + 1, preorder.end()); // vector切片【初始化截取】
        vector<int> inorderRight(inorder.begin() + rootIdx + 1, inorder.end()); // vector切片【初始化截取】
        root->right = buildTree(preorderRight, inorderRight);
 
        return root;
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        # 递归结束条件
        if not preorder:
            return None
        root_val = preorder[0]
        root_idx = inorder.index(root_val)
        root = TreeNode(root_val)
 
        # 前序遍历中,索引root_idx前的节点为根+左子树,preorder[1: root_idx + 1]为左子树数组
        # 中序遍历中,索引root_idx为根节点,inorder[0: root_idx]为左子树数组
        root.left = self.buildTree(preorder[1:root_idx + 1], inorder[0:root_idx])
 
        # 索引root_idx后的节点为右子树所有节点,preorder[root_idx + 1:]为右子树数组
        # 中序遍历中,索引root_idx为根节点,inorder[root_idx + 1: ]为右子树数组
        root.right = self.buildTree(preorder[root_idx + 1:], inorder[root_idx + 1:])
        return root

方法二:迭代【O(n),其中 n 是树中的节点个数】

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder:
            return None
 
        root = TreeNode(preorder[0])
        stack = [root]
        inorderIndex = 0
        for i in range(1, len(preorder)):
            preorderVal = preorder[i]
            node = stack[-1]
            if node.val != inorder[inorderIndex]:
                node.left = TreeNode(preorderVal)
                stack.append(node.left)
            else:
                while stack and stack[-1].val == inorder[inorderIndex]:
                    node = stack.pop()
                    inorderIndex += 1
                node.right = TreeNode(preorderVal)
                stack.append(node.right)
 
        return root

106-从中序与后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。

注意:你可以假设树中没有重复的元素。

例如,给出

中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

/**
 * 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* buildTree(vector<int>& inorder, vector<int>& postorder) {
        // 递归结束条件
        if(!postorder.size()){
            return nullptr;
        }
        int rootVal = postorder.back();
        int rootIdx = find(inorder.begin(), inorder.end(), rootVal) - inorder.begin();

        TreeNode* root = new TreeNode(rootVal);

        // 中序遍历中,索引rootIdx为根节点,inorder[0: rootIdx]为左子树数组
        vector<int> inorderLeft(inorder.begin(), inorder.begin() + rootIdx);
        // 后序遍历中,索引rootIdx前的节点为左子树,postorder[0: rootIdx]为左子树数组
        vector<int> postorderLeft(postorder.begin(), postorder.begin() + rootIdx);

        root->left = buildTree(inorderLeft, postorderLeft);

        // 中序遍历中,索引rootIdx为根节点,inorder[rootIdx+1: ]为右子树数组
        vector<int> inorderRight(inorder.begin() + rootIdx + 1, inorder.end());
        // 后序遍历中,索引rootIdx后到倒数第2的节点为右子树所有节点,preorder[rootIdx:]为右子树数组
        vector<int> postorderRight(postorder.begin() + rootIdx, postorder.end() - 1);

        root->right = buildTree(inorderRight, postorderRight);

        return root;
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
        # 递归结束条件
        if len(postorder) == 0:
            return None
        
        currNode = TreeNode(postorder[-1])
        indexCurrNode = inorder.index(currNode.val)


        # 中序遍历中,索引indexCurrNode为根节点,inorder[0: indexCurrNode]为左子树数组
        # 后序遍历中,索引indexCurrNode前的节点为左子树,postorder[0: indexCurrNode]为左子树数组
        currNode.left = self.buildTree(inorder[0: indexCurrNode], postorder[0:indexCurrNode])

        # 中序遍历中,索引indexCurrNode为根节点,inorder[indexCurrNode + 1: ]为右子树数组
        # 后序遍历中,索引indexCurrNode后到倒数第2的节点为右子树所有节点,preorder[indexCurrNode:-1]为右子树数组
        currNode.right = self.buildTree(inorder[indexCurrNode + 1 :], postorder[indexCurrNode : -1])

        return currNode

剑指 Offer 27-二叉树的镜像【226-翻转二叉树】

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例1:
在这里插入图片描述

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例 2:
在这里插入图片描述

输入:root = [2,1,3]
输出:[2,3,1]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目范围在 [0, 100] 内
  • -100 <= Node.val <= 100

备注:这个问题是受到 Max Howell 的 原问题 启发的 :

谷歌:我们90%的工程师使用您编写的软件(Homebrew),但是您却无法在面试时在白板上写出翻转二叉树这道题,这太糟糕了。


/**
 * 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){
            return nullptr;
        }
        auto temp = root->left;
        root->left = root->right;
        root->right = temp;
        invertTree(root->left);
        invertTree(root->right);
        return root;
    }
};
# Definition for a binary tree node.
# class TreeNode:#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        def dfs(node:TreeNode)-
            if node is None:    # 递归终止条件:当深入到叶子节点的下一个节点(空节点)时,停止遍历
                return
            
            # 主体逻辑部分
            temp = node.left
            node.left = node.right
            node.right = temp

            dfs(node.left)  # 递归翻转当前节点左子树
            dfs(node.right) # 递归翻转当前节点右子树

        dfs(root)
        return root
/**
 * 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) {
        dfs(root);
        return root;
    }
    void dfs(TreeNode* node){
        if(!node){
            return;
        }
        auto temp = node->left;
        node->left = node->right;
        node->right = temp;

        dfs(node->left);
        dfs(node->right);
    }
};

617-合并二叉树

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:
在这里插入图片描述

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]

提示:

  • 两棵树中的节点数目在范围 [0, 2000] 内
  • − 1 0 4 < = N o d e . v a l < = 1 0 4 -10^4 <= Node.val <= 10^4 104<=Node.val<=104

# Definition for a binary tree node.
# class TreeNode:#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:

        def dfs(node1:TreeNode, node2:TreeNode)->TreeNode-
            # 迭代终止条件
            if node1 is None and node2 is None:
                return None
            if node1 is not None and node2 is None-
                return node1
            if node1 is None and node2 is not None-
                return node2

            # 主体逻辑部分:合并当前节点
            mergedNode = TreeNode(node1.val + node2.val)

            # 递归
            mergedNode.left = dfs(node1.left, node2.left)
            mergedNode.right = dfs(node1.right, node2.right)

            return mergedNode   # 返回合并后的当前节点作为上一节点的子节点
        
        mergedTree = dfs(root1, root2)
        return mergedTree
/**
 * 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* mergeTrees(TreeNode* root1, TreeNode* root2) {
        auto mergedTree = dfs(root1, root2);
        return mergedTree;
    }

    TreeNode* dfs(TreeNode* node1, TreeNode* node2){
        if(!node1 && !node2){
            return nullptr;
        }
        if(node1 && !node2){
            return node1;
        }
        if(!node1 && node2){
            return node2;
        }

        // 主体逻辑部分:合并当前节点
        TreeNode* mergedNode = new TreeNode(node1->val + node2->val);
        // 递归
        mergedNode->left = dfs(node1->left, node2->left);
        mergedNode->right = dfs(node1->right, node2->right);

        return mergedNode;  // 返回合并后的当前节点作为上一节点的子节点
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
        # 迭代终止条件
        if root1 is None and root2 is None:
            return None
        if root1 is not None and root2 is None:
            return root1
        if root1 is None and root2 is not None:
            return root2

        # 主体逻辑部分:合并当前节点
        mergedNode = TreeNode(root1.val + root2.val)
        
        # 递归
        mergedNode.left = self.mergeTrees(root1.left, root2.left)
        mergedNode.right = self.mergeTrees(root1.right, root2.right)

        return mergedNode
/**
 * 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* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(!root1 && !root2){
            return nullptr;
        }
        if(root1 && !root2){
            return root1;
        }
        if(!root1 && root2){
            return root2;
        }

        // 主体逻辑部分:合并当前节点
        TreeNode* mergedNode = new TreeNode(root1->val + root2->val);

        // 递归
        mergedNode->left = mergeTrees(root1->left, root2->left);
        mergedNode->right = mergeTrees(root1->right, root2->right);

        return mergedNode;
    }
};

654-最大二叉树

给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:

  1. 二叉树的根是数组 nums 中的最大元素。
  2. 左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
  3. 右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。

返回有给定数组 nums 构建的 最大二叉树 。

示例 1:
在这里插入图片描述

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:
- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
        - 空数组,无子节点。
        - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
            - 空数组,无子节点。
            - 只有一个元素,所以子节点是一个值为 1 的节点。
    - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
        - 只有一个元素,所以子节点是一个值为 0 的节点。
        - 空数组,无子节点。

示例 2:
在这里插入图片描述

输入:nums = [3,2,1]
输出:[3,null,2,null,1]

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000
  • nums 中的所有整数 互不相同

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
        if not nums: return None
        # 由于没有重复元素, 所以获取最大元素部分代码等价的
        # max_v, m_i = float(-inf), 0
        # for i, v in enumerate(nums):
        #     if v>max_v:
        #         max_v = v
        #         m_i = i
        max_v = max(nums)
        m_i = nums.index(max_v)
        root = TreeNode(max_v)
        root.left = self.constructMaximumBinaryTree(nums[:m_i])
        root.right = self.constructMaximumBinaryTree(nums[m_i+1:])
        return root
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:        
        return self.dfs(nums)

    def dfs(self, nums):
        if not nums:
            return None
        root_val = max(nums)
        root_idx = nums.index(root_val)
        root = TreeNode(root_val)
        root.left = self.dfs(nums[:root_idx])
        root.right = self.dfs(nums[root_idx + 1:])
        return root
/**
 * 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* constructMaximumBinaryTree(vector<int>& nums) {
        return dfs(nums, 0, nums.size() - 1);
    }

    TreeNode* dfs(vector<int>& nums, int left, int right){
        if(left > right){
            return nullptr;
        }

        int rootIdx = left;
        for(int i = left + 1; i <= right; i++){
            if(nums[i] > nums[rootIdx]){
                rootIdx = i;
            }
        }
        int rootVal = nums[rootIdx];

        TreeNode* node = new TreeNode(rootVal);
        node->left = dfs(nums, left, rootIdx - 1);
        node->right = dfs(nums, rootIdx + 1, right);

        return node;
    }
};

五、二叉树的公共祖先问题

236-二叉树的最近公共祖先【剑指 Offer 68 - II. 二叉树的最近公共祖先】

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 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 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

提示:

  • 树中节点数目在范围 [ 2 , 1 0 5 ] [2, 10^5] [2,105] 内。
  • − 1 0 9 < = N o d e . v a l < = 1 0 9 -10^9 <= Node.val <= 10^9 109<=Node.val<=109
  • 所有 Node.val 互不相同 。
  • p != q
  • p 和 q 均存在于给定的二叉树中。

方法一:递归回溯(后序遍历:左->右->根)

祖先的定义: 若节点 p 在节点 root 的左(右)子树中,或 p = root ,则称 root 是 p 的祖先。

在这里插入图片描述
最近公共祖先的定义: 设节点 root 为节点 p, q 的某公共祖先,若其左子节点 root.left 和右子节点 root.right 都不是 p,q 的公共祖先,则称 root 是 “最近的公共祖先” 。

根据以上定义,若 root 是 p, q 的 最近公共祖先 ,则只可能为以下情况之一:

  • p 和 q 在 root 的子树中,且分列 root 的 异侧(即分别在左、右子树中);
  • p = root ,且 q 在 root 的左或右子树中;
  • q = root ,且 p 在 root 的左或右子树中;

在这里插入图片描述
考虑通过递归对二叉树进行后序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p, q 在节点 root 的异侧时,节点 root 即为最近公共祖先,则向上返回 root 。

递归解析:

  • 终止条件:
    1. 当越过叶节点,则直接返回 null ;
    2. 当 root 等于 p, q ,则直接返回 root ;
  • 递推工作:
    1. 开启递归左子节点,返回值记为 left ;
    2. 开启递归右子节点,返回值记为 right ;
  • 返回值: 根据 left 和 right ,可展开为四种情况;
    1. 当 left 和 right 同时不为空 :说明 p, q 分列在 root 的 异侧 (分别在 左 / 右子树),因此 root 为最近公共祖先,返回 root ;
    2. 当 left 为空 ,right 不为空 :p,q 都不在 root 的左子树中,直接返回 right 。具体可分为两种情况:
      1. p,q 其中一个在 root 的 右子树 中,此时 right 指向 p(假设为 p );
      2. p,q 两节点都在 root 的 右子树 中,此时的 right 指向 最近公共祖先节点 ;
    3. 当 left 不为空 , right 为空 :与情况 3. 同理;
    4. 当 left 和 right 同时为空 :说明 root 的左 / 右子树中都不包含 p,q ,返回 null ;

观察发现, 情况 4. 可合并至 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:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root){
            return nullptr;
        }
        if(root == p || root == q){
            return root;
        }
        auto left = lowestCommonAncestor(root->left, p, q);
        auto right = lowestCommonAncestor(root->right, p, q);
        if(left && right){
            return root;
        }else if(left){
            return left;
        }else{
            return right;
        }
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        # 递归结束条件
        if not root:    
            return None
        
        # 递归结束条件:找到p/q节点
        if root == p or root == q:
            return root
        
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)

        if left and right:  # 如果在左子树、右子树中都找到p或q
            return root
        if left:    # 只在左子树找到p或q
            return left
        if right:   # 只在右子树找到p或q
            return right
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        def dfs(node):
            # 递归结束条件
            if not node:    
                return None
            
            # 递归结束条件:找到p/q节点
            if node == p or node == q:
                return node
            
            left = dfs(node.left)
            right = dfs(node.right)

            if left and right:  # 如果在左子树、右子树中都找到p或q
                return node
            if left:    # 只在左子树找到p或q
                return left
            if right:   # 只在右子树找到p或q
                return right
        
        return dfs(root)

235-二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

在这里插入图片描述

示例 1:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和节点 8 的最近公共祖先是 6。

示例 2:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

说明:

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉搜索树中。

方法一:递归(后序遍历:左->右->根)【不用中间变量result】

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val > q.val:
            p, q = q, p

        def dfs(node):
            if not node:
                return None
            
            left = dfs(node.left)
            right = dfs(node.right)

            if p.val <= node.val <= q.val:
                return node
            if node.val < p.val:
                return right
            if node.val > q.val:
                return left

        return dfs(root)

方法二:递归(后序遍历:左->右->根)【用中间变量result(不用return结束)】

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val > q.val:
            p, q = q, p

        result = None

        def dfs(node):

            nonlocal result

            if not node:
                return


            dfs(node.left)
            dfs(node.right)


            if p.val <= node.val <= q.val:
                result = node


        dfs(root)
        return result

方法三:递归(前序遍历:根->左->右)【用中间变量result(需要用return结束)】

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val > q.val:
            p, q = q, p

        result = None

        def dfs(node):

            nonlocal result

            if not node:
                return

            if p.val <= node.val <= q.val:
                result = node
                return

            dfs(node.left)
            dfs(node.right)

        dfs(root)
        return result

方法四:递归(中序遍历:左->根->右)【用中间变量result(需要用return结束)】

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val > q.val:
            p, q = q, p

        result = None

        def dfs(node):

            nonlocal result

            if not node:
                return

            dfs(node.left)

            if p.val <= node.val <= q.val:
                result = node
                return
            
            dfs(node.right)

        dfs(root)
        return result

方法五:迭代

这题让求二叉搜索树的最近公共祖先,而二叉搜索树的特点就是 左子树的所有节点都小于当前节点,右子树的所有节点都大于当前节点,并且每棵子树都具有上述特点,所以这题就好办了,从根节点开始遍历:

  • 如果两个节点值都小于根节点,说明他们都在根节点的左子树上,我们往左子树上找;
  • 如果两个节点值都大于根节点,说明他们都在根节点的右子树上,我们往右子树上找;
  • 如果一个节点值大于根节点,一个节点值小于根节点,说明他们他们一个在根节点的左子树上一个在根节点的右子树上,那么根节点就是他们的最近公共祖先节点。

画个图看一下,比如要找0和5的最近公共祖先节点,如下图所示
在这里插入图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val > q.val:
            p, q = q, p

        while True:
            if p.val <= root.val <= q.val:
                return root
            if root.val < p.val:
                root = root.right
            if root.val > q.val:
                root = root.left

方法六:用二叉树的搜索方法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        def dfs(node):
            if node is None:
                return None

            if node == p or node == q:
                return node
            
            left = dfs(node.left)     # 在 node 的左子树 查找p或q
            right = dfs(node.right)   # 在 node 的右子树 查找p或q

            if left and right:  # 两边都有,则当前节点就是最近公共祖先
                return node
                
            if left:     # 在左边
                return left
            
            if right:     # 在右边
                return right


        return dfs(root)

六、二叉树之间的关系

100-相同的树

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:
在这里插入图片描述

输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2:
在这里插入图片描述

输入:p = [1,2], q = [1,null,2]
输出:false

示例 3:
在这里插入图片描述

输入:p = [1,2,1], q = [1,1,2]
输出:false

提示:

  • 两棵树上的节点数目都在范围 [0, 100] 内
  • − 1 0 4 < = N o d e . v a l < = 1 0 4 -10^4 <= Node.val <= 10^4 104<=Node.val<=104

/**
 * 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 isSameTree(TreeNode* p, TreeNode* q) {
        if(!p && !q){
            return true;
        }
        if(!p || !q){
            return false;
        }

        bool currIsSame = (p->val == q->val);

        bool leftIsSame = isSameTree(p->left, q->left);
        bool rightIsSame = isSameTree(p->right, q->right);

        return currIsSame and leftIsSame and rightIsSame;
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        # 递归结束条件
        if p is None and q is None:
            return True
        if p is None and q is not None:
            return False
        if p is not None and q is None:
            return False
        
        # 逻辑主体部分
        curr_is_same = p.val == q.val

        # 递归
        left_is_same = self.isSameTree(p.left, q.left)
        right_is_same = self.isSameTree(p.right, q.right)
        

        return curr_is_same and left_is_same and right_is_same

572-另一个树的子树

给定两个非空二叉树 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。


  • 判断root与subRoot是否相同
  • subRoot是否是root的子树
    • root.left与subRoot相同
    • root.right与subRoot相同
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSubtree(self, root: TreeNode, subRoot: TreeNode) -> bool:

        def isSame(node1:TreeNode, node2:TreeNode)->bool:
            if node1 is None and node2 is None:
                return True
            if node1 is None and node2 is not None:
                return False
            if node1 is not None and node2 is None:
                return False

            curr_is_same = node1.val == node2.val
            left_is_same = isSame(node1.left, node2.left)
            right_is_same = isSame(node1.right, node2.right)

            return curr_is_same and left_is_same and right_is_same


        if root is None and subRoot is None:
            return True
        if root is None and subRoot is not None:
            return False
        if root is not None and subRoot is None:
            return False

        is_same = isSame(root, subRoot)
        is_sub = self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)

        result = is_same or is_sub
        
        return result     
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSubtree(self, root: TreeNode, subRoot: TreeNode) -> bool:        
        if not root:
            return False
        
        return self.isSame(root, subRoot) or self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)


    def isSame(self, node1, node2):
        if not node1 and not node2:
            return True
        if not node1:
            return False
        if not node2:
            return False
        if node1.val != node2.val:
            return False
            
        return self.isSame(node1.left, node2.left) and self.isSame(node1.right, node2.right)
/**
 * 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 isSubtree(TreeNode* root, TreeNode* subRoot) {
        if(!root){
            return false;
        }
        return isSame(root, subRoot) or isSubtree(root->left, subRoot) or isSubtree(root->right, subRoot);
    }

    bool isSame(TreeNode* node1, TreeNode* node2){
        if(!node1 && !node2){
            return true;
        }
        if(!node1){
            return false;
        }
        if(!node2){
            return false;
        }
        if(node1->val != node2->val){
            return false;
        }

        return isSame(node1->left, node2->left) and isSame(node1->right, node2->right); 
    }
};

剑指 Offer 26-树的子结构

输入两棵二叉树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


在这里插入代码片
/**
 * 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 isSubStructure(TreeNode* A, TreeNode* B) {
        if(!A || !B){
            return false;
        }
        return isSame(A, B) || isSubStructure(A->left, B) || isSubStructure(A->right, B);
    }

    bool isSame(TreeNode* node1, TreeNode* node2){
        if(!node1 && !node2){
            return true;
        }
        if(!node1){
            return false;
        }
        if(!node2){
            return true;
        }
        if(node1->val != node2->val){
            return false;
        }
        return isSame(node1->left, node2->left) && isSame(node1->right, node2->right);
    }
};
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        if not A or not B:
            return False
        return self.isSame(A, B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B)

    def isSame(self, node1, node2):
        if not node1 and not node2:
            return True
        if not node1:
            return False
        if not node2:
            return True
        if node1.val != node2.val:
            return False
        return self.isSame(node1.left, node2.left) and self.isSame(node1.right, node2.right)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        def isSame(node1, node2):
            if not node1 and not node2:
                return True
            if not node1:
                return False
            if not node2:
                return True
            if node1.val != node2.val:
                return False
            return isSame(node1.left, node2.left) and isSame(node1.right, node2.right)

        if not A or not B:
            return False
        return isSame(A, B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值