一、二叉树的遍历方式
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注意点:
-
如果是找路径和等于给定target的路径的,那么可以不用新增一个临时变量cursum来判断当前路径和,
只需要用给定和target减去节点值,最终结束条件判断target==0即可 -
是否要回溯:二叉树的问题大部分是不需要回溯的,原因如下:
二叉树的递归部分:dfs(root->left),dfs(root->right)已经把可能的路径穷尽了,
因此到任意叶节点的路径只可能有一条,绝对不可能出现另外的路径也到这个满足条件的叶节点的;
而对比二维数组(例如迷宫问题)的DFS,for循环向四个方向查找每次只能朝向一个方向,并没有穷尽路径,
因此某一个满足条件的点可能是有多条路径到该点的
并且visited数组标记已经走过的路径是会受到另外路径是否访问的影响,这时候必须回溯 -
找到路径后是否要return:
取决于题目是否要求找到叶节点满足条件的路径,如果必须到叶节点,那么就要return;
但如果是到任意节点都可以,那么必不能return,因为这条路径下面还可能有更深的路径满足条件,还要在此基础上继续递归 -
是否要双重递归(即调用根节点的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注意点:
- left,right代表的含义要根据题目所求设置,比如最长路径、最大路径和等等
- 全局变量res的初值设置是0还是INT_MIN要看题目节点是否存在负值,如果存在就用INT_MIN,否则就是0
- 注意两点之间路径为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,3∗104]
- -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<=231−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;
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 。一个以此数组直接递归构建的 最大二叉树 定义如下:
- 二叉树的根是数组 nums 中的最大元素。
- 左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
- 右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 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 。
递归解析:
- 终止条件:
- 当越过叶节点,则直接返回 null ;
- 当 root 等于 p, q ,则直接返回 root ;
- 递推工作:
- 开启递归左子节点,返回值记为 left ;
- 开启递归右子节点,返回值记为 right ;
- 返回值: 根据 left 和 right ,可展开为四种情况;
- 当 left 和 right 同时不为空 :说明 p, q 分列在 root 的 异侧 (分别在 左 / 右子树),因此 root 为最近公共祖先,返回 root ;
- 当 left 为空 ,right 不为空 :p,q 都不在 root 的左子树中,直接返回 right 。具体可分为两种情况:
- p,q 其中一个在 root 的 右子树 中,此时 right 指向 p(假设为 p );
- p,q 两节点都在 root 的 右子树 中,此时的 right 指向 最近公共祖先节点 ;
- 当 left 不为空 , right 为空 :与情况 3. 同理;
- 当 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)