二叉树可以链式存储,也可以顺序存储。
链式存储方式就用指针, 顺序存储的方式用数组。
二叉树链式存储定义
C++
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x): val(x), left(NULL), right(NULL) {}
};
Python
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
递归算法分三步来写:
144
题目:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
输入:root = [1,null,2,3]
输出:[1,2,3]
思路:前序:根——左——右
笔记:C++中push_back()
函数用于在vector最后添加一个元素。
C++:
class Solution {
public:
void preorder(TreeNode *root, vector<int> &res){
if (root == nullptr) return;
res.push_back(root->val);
preorder(root->left, res);
preorder(root->right, res);
}
vector<int> preorderTraversal(TreeNode *root) {
vector<int> res; //保存结果
preorder(root, res);
return res;
}
};
Python:
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# 保存的结果
result = []
def preorder(root: TreeNode):
if root == None:
return
result.append(root.val)
preorder(root.left)
preorder(root.right)
preorder(root)
return result
94
题目:给你二叉树的根节点 root ,返回它节点值的 中序 遍历。
输入:root = [1,null,2,3]
输出:[1,3,2]
思路:中序:左——根——右
C++:
class Solution {
public:
void inorder(TreeNode *root, vector<int> &res){
if(root == nullptr) return;
inorder(root->left, res);
res.push_back(root->val);
inorder(root->right, res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
inorder(root, res);
return res;
}
};
Python:
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def inorder(root: TreeNode):
if root == None:
return
inorder(root.left)
result.append(root.val)
inorder(root.right)
inorder(root)
return result
145
题目:给你二叉树的根节点 root ,返回它节点值的 后序 遍历。
输入:root = [1,null,2,3]
输出:[3,2,1]
思路:后序:左——右——根
C++:
class Solution {
public:
void postorder(TreeNode *root, vector<int> &res){
if (root == nullptr) return;
postorder(root->left, res);
postorder(root->right, res);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
postorder(root, res);
return res;
}
};
Python:
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def postorder(root: TreeNode):
if root == None:
return
postorder(root.left)
postorder(root.right)
result.append(root.val)
postorder(root)
return result
后续补充…
后续补充…
102
题目:给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
思路:需要借用一个辅助队列来实现,队列先进先出,符合一层一层遍历的逻辑。
笔记:C++中que.front()
函数返回队列的前端元素。
python中队列操作常采用from collections import deque
,deque为双端队列。
其中,append()
是从右端入队,popleft()
是从左端移除
C++:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que; //定义队列
if(root != nullptr) que.push(root); //根入队
vector<vector<int>> result; //结果为二维数组
while(!que.empty()){
int size = que.size();
// 内层数组:每一层的结点
vector<int> res;
// 用固定大小size,不要使用que.size(),因为que.size是不断变化的
for(int i = 0; i < size; i++){
// 队头写到结果里
TreeNode *node = que.front();
que.pop();
// 队头写到结果里
res.push_back(node->val);
// 再把他的左右孩子入队
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(res); //每层res再写入外层数组中
}
return result;
}
};
Python:
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
results = []
if root == None:
return results
from collections import deque
# root入队
que = deque([root])
while que:
size = len(que)
# 内层数组
result = []
for _ in range(size):
# 弹出一个值作为node
node = que.popleft()
# node存入内层中
result.append(node.val)
# 把他的左右孩子入队
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
results.append(result)
return results
107
题目:给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]
思路:就是把经典层序遍历最后的result数组反转一下即可
笔记:
C++:
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> que; //定义队列
if(root != nullptr) que.push(root); //根入队
vector<vector<int>> result; //结果为二维数组
while(!que.empty()){
int size = que.size();
// 内层数组:每一层的结点
vector<int> res;
// 用固定大小size,不要使用que.size(),因为que.size是不断变化的
for(int i = 0; i < size; i++){
// 队头写到结果里
TreeNode *node = que.front();
que.pop();
// 队头写到结果里
res.push_back(node->val);
// 再把他的左右孩子入队
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(res); //每层res再写入外层数组中
}
// 反转数组
reverse(result.begin(), result.end());
return result;
}
};
Python:
class Solution:
def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
results = []
if root == None:
return results
from collections import deque
# root入队
que = deque([root])
while que:
size = len(que)
# 内层数组
result = []
for _ in range(size):
# 弹出一个值作为node
node = que.popleft()
# node存入内层中
result.append(node.val)
# 把他的左右孩子入队
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
results.append(result)
results.reverse()
return results
199
题目:给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
思路:层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (i == (size - 1)) result.push_back(node->val); // 将每一层的最后元素放入result数组中
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
637
题目:给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。
输入:root = [3,9,20,null,null,15,7]
输出:[3.00000,14.50000,11.00000]
解释:第 0 层的平均值为 3,第 1 层的平均值为 14.5,第 2 层的平均值为 11 。
因此返回 [3, 14.5, 11] 。
思路:层序遍历的时候把一层求个总和在取一个均值。
C++:
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
sum += node->val;
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(sum / size); // 将每一层均值放进结果集
Python:
while que:
size = len(que)
sum_ = 0
for _ in range(size):
cur = que.popleft()
sum_ += cur.val
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
results.append(sum_ / size)
429
题目:给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:[[1],[2,3,4,5],[6,7,8,9,10],[11,12,13],[14]]
思路:左孩右孩变成children数组
笔记:Python:deque中extend()
函数表示将一个list的值全部入队。
C++:
for (int i = 0; i < size; i++) {
Node* node = que.front();
que.pop();
vec.push_back(node->val);
for (int i = 0; i < node->children.size(); i++) { // 将节点孩子加入队列
if (node->children[i]) que.push(node->children[i]);
}
}
result.push_back(vec);
Python:
while que:
result = []
for _ in range(len(que)):
cur = que.popleft()
result.append(cur.val)
# cur.children 是 Node 对象组成的列表,也可能为 None
if cur.children:
que.extend(cur.children)
results.append(result)
515
题目:给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。
输入: root = [1,3,2,5,3,null,9]
输出: [1,3,9]
思路:每层for循环中每次都比较最大值
笔记:
C++:
int maxValue = INT_MIN; // 取每一层的最大值
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
maxValue = node->val > maxValue ? node->val : maxValue;
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(maxValue); // 把最大值放进数组
Python:
while que:
cur = -inf
for _ in range(len(que)):
node = que.popleft()
cur = max(cur, node.val)
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
results.append(cur)
116
题目:给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,'#' 标志着每一层的结束。
思路:
笔记:
C++:
class Solution {
public:
Node* connect(Node* root) {
queue<Node*> que;
if (root != NULL) que.push(root);
while (!que.empty()) {
int size = que.size();
Node* nodePre; // 前一个节点
Node* node; // 当前节点
for (int i = 0; i < size; i++) {
if (i == 0) {
nodePre = que.front(); // 取出一层的头结点
que.pop();
node = nodePre;
} else {
node = que.front(); // 取出当前节点
que.pop();
nodePre->next = node; // 前一个节点指向当前节点
nodePre = nodePre->next; // 前一节点往后移
}
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
nodePre->next = NULL; // 本层最后一个节点指向NULL
}
return root;
}
};
Python:
迭代法
def connect(self, root: 'Node') -> 'Node':
if not root:
return
if root.left:
root.left.next = root.right
if root.next:
root.right.next = root.next.left
self.connect(root.left)
self.connect(root.right)
return root
层次遍历法
import collections
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return root
# 初始化队列同时将第一层节点加入队列中,即根节点
Q = collections.deque([root])
# 外层的 while 循环迭代的是层数
while Q:
# 记录当前队列大小
size = len(Q)
# 遍历这一层的所有节点
for i in range(size):
# 从队首取出元素
node = Q.popleft()
# 连接
if i < size - 1: # size-1连的是NULL,不需要做处理
node.next = Q[0] #因为当前节点已经从队列中pop了,Q[0]即下一个节点
# 拓展下一层节点
if node.left:
Q.append(node.left)
if node.right:
Q.append(node.right)
# 返回根节点
return root
104
题目:给定一个二叉树,找出其最大深度
思路:return len(results)
即可。
C++:
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == NULL) return 0;
int depth = 0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size();
depth++; // 记录深度
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return depth;
}
};
Python:
class Solution:
def maxDepth(self, root: TreeNode) -> int:
results = []
if root == None:
return len(results)
from collections import deque
# root入队
que = deque([root])
while que:
size = len(que)
# 内层数组
result = []
for _ in range(size):
# 弹出一个值作为node
node = que.popleft()
# node存入内层中
result.append(node.val)
# 把他的左右孩子入队
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
results.append(result)
return len(results)
111
题目:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
输入:root = [3,9,20,null,null,15,7]
输出:2
思路:和最大深度一样,只是判定条件为:左右孩都为空。
笔记:
C++:
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
int depth = 0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size();
depth++; // 记录最小深度
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
if (!node->left && !node->right) { // 当左右孩子都为空的时候,说明是最低点的一层了,退出
return depth;
}
}
}
return depth;
}
};
Python:
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
from collections import deque
# root入队
que = deque([root])
depth = 0
while que:
size = len(que)
# 内层数组
depth += 1
for _ in range(size):
# 弹出一个值作为node
node = que.popleft()
# 把他的左右孩子入队
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
if node.left == None and node.right == None:
return depth