0 二叉树的遍历
前序法:访问根结点→左子树→右子树 口诀:根左右
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
if not root:
return res
def dfs(root):
res.append(root.val)
if root.left:
dfs(root.left)
if root.right:
dfs(root.right)
dfs(root)
return res
中序法:访问左子树→根结点→右子树 口诀:左根右
后序法:访问左子树→右子树→ 根结点 口诀:左右根
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
res1,res2,res3 = [],[],[]
class Solution:
def preorder(self, root: TreeNode):
if root:
res1.append(root.val)
self.preorder(root.left)
self.preorder(root.right)
return res1
def midorder(self, root: TreeNode):
if root:
self.midorder(root.left)
res2.append(root.val)
self.midorder(root.right)
return res2
def lastorder(self, root: TreeNode):
if root:
self.lastorder(root.left)
self.lastorder(root.right)
res3.append(root.val)
return res3
def threeOrders(self , root: TreeNode) -> List[List[int]]:
ret = []
ret.append(self.preorder(root))
ret.append(self.midorder(root))
ret.append(self.lastorder(root))
return ret
1 二叉树镜像
struct TreeNode* mirrorTree(struct TreeNode* root){
if(root == NULL)
return root;
struct TreeNode * tmp = root->right;
root->right = root->left;
root->left = tmp;
mirrorTree(root->right);
mirrorTree(root->left);
return root;
}
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
if not root: return root
root.left, root.right = root.right, root.left
self.mirrorTree(root.left)
self.mirrorTree(root.right)
return root
栈的思想
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
if not root: return root
stack = [root]
while stack:
node = stack.pop(0)
if node.left: stack.append(node.left)
if node.right: stack.append(node.right)
node.left, node.right = node.right, node.left # key operation
return root
2 二叉树的深度
对于每个根节点来说,寻找其每个子节点的最大深度
先序遍历,递归实现
int maxDepth(struct TreeNode* root){
if(root == NULL)
return 0;
else
return fmax(maxDepth(root->left), maxDepth(root->right)) + 1;
}
层序遍历:
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
queue,res = [root], 0
while queue:
t = []
for node in queue:
if node.left: t.append(node.left)
if node.right: t.append(node.right)
queue = t
res += 1
return res
3 二叉搜索树中第k大的节点
给定一棵二叉搜索树,请找出其中第k大的节点。
二叉搜索树:左子树不大于根节点、右子树不小于根节点
要点:二叉搜索树的中序遍历为 递增序列
思路:首先申请一个数组空间,保存二叉搜索树的中序遍历,输出第 k-1 位,这里注意我们在中序遍历的时候使用的是先右子树在左子树,这样得到的中序遍历是 递减序列,这样我们直接输出 k-1 即为第 k 大的节点了。
void func(struct TreeNode *root, int *count, int *res)
{
if(root != NULL) {
func(root->right, count, res);
res[(*count)++] = root->val;
func(root->left, count, res);
}
}
int kthLargest(struct TreeNode* root, int k){
int *res = (int *)malloc(sizeof(int)*10000);
int count = 0;
func(root, &count, res);
return res[k-1];
}
层序遍历,取出所有的元素,排序后输出
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
que = [root]
t = []
len_que = len(que)
while que:
for _ in range(len(que)):
node = que.pop(0)
t.append(node.val)
if node.left: que.append(node.left)
if node.right: que.append(node.right)
len_que = len(que)
t.sort(reverse=True)
return t[k-1]
中序遍历
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
def dfs(root):
if not root: return
dfs(root.right)
if self.k == 0: return
self.k -= 1
if self.k == 0: self.res = root.val
dfs(root.left)
self.k = k
dfs(root)
return self.res
4 二叉树的最近公共祖先
最近公共祖先的定义为:对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
思路:
lowestCommonAncestor(root, p, q) 的功能就是找出以 root 为根节点的两个节点 p q 的最近公共祖先,所以递归体要分三种情况讨论:
如果 p q 分别是 root 的左右节点,那么 root 就是我们要找的最近的公共祖先
如果 p q 都是 root 的右节点,那么返回 lowestCommonAncestor(root->right, p, q)
如果 p q 都是 root 的左节点,那么返回 lowestCommonAncestor(root->left, p, q)
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q){
if(root == NULL || root == p || root == q)
return root;
struct TreeNode * left = lowestCommonAncestor(root->left, p, q);
struct TreeNode * right = lowestCommonAncestor(root->right, p, q);
if(left != NULL && right != NULL)
return root;
if(left == NULL && right != NULL)
return right;
if(left != NULL && right == NULL)
return left;
else
return NULL;
}
5 二叉搜索树的最近公共祖先
此题与第4题类似,但条件不同的是二叉树,此题为二叉搜索树,二叉搜索树有一个性质就是左子树的值小于根节点,右子树的值大于根节点
思路一:同第四题
思路二:
当 p q 都是右子树时,root = root->right
当 p, q 都在左子树时, root = root->left
否则,说明找到了 最近公共祖先 ,跳出
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
while(root != NULL)
{
if(root->val < q->val && root->val < p->val){
root = root->right;
}
else if(root->val > q->val && root->val > p->val){
root = root->left;
} else {
break;
}
}
return root;
}
思路三: 递归,原理是一样的
truct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
while(root != NULL)
{
if(root->val < q->val && root->val < p->val){
return lowestCommonAncestor(root->right, p, q);
}
else if(root->val > q->val && root->val > p->val){
return lowestCommonAncestor(root->left, p, q);
} else {
break;
}
}
return root;
}
6 平衡二叉树
平衡二叉树的定义是:任意节点的左右子树的深度不超过1
思路1:先序遍历求深度+判断深度
int max_dep(struct TreeNode* root)
{
if(root == NULL)
return 0;
else
return fmax(max_dep(root->left), max_dep(root->right)) + 1;
}
bool isBalanced(struct TreeNode* root){
if(root == NULL)
return true;
else
return (fabs(max_dep(root->right)-max_dep(root->left)) <= 1
&& isBalanced(root->left) && isBalanced(root->right));
}
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def depth(root):
if not root: return 0
return max(depth(root.left), depth(root.right)) + 1
if not root: return True
return abs(depth(root.left)-depth(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right)
思路2:后序遍历 + 剪枝
后续遍历的顺序是 左右根
我们通过判断节点的左右子树的深度差,如果小于等于1,就返回子树的深度,否则直接返回 -1 表示当前二叉树不是平衡二叉树。
int func(struct TreeNode* root)
{
if(root == NULL)
return 0;
int left = func(root->left);
int right = func(root->right);
if(left == -1 || right == -1)
return -1;
return fabs(left-right) < 2 ? fmax(left, right)+1 :-1;
}
bool isBalanced(struct TreeNode* root){
if(root == NULL)
return true;
else
return func(root) != -1;
}
7 对称二叉树
思路:对称二叉树有一个性质,那就是对称节点的值相等,以及
L.left.val = R.right.val
L.right.val = R.left.val
注意递归结束的边界:
左节点和右节点都为空 -> 到底了都长得一样 ->true
左节点为空的时候右节点不为空,或反之 -> 长得不一样-> false
左右节点值不相等 -> 长得不一样 -> false
int func(struct TreeNode* p, struct TreeNode* q)
{
if(p == NULL && q == NULL)
return true;
else if (p == NULL || q == NULL || p->val != q->val)
return false;
else
return func(p->left, q->right) && func(p->right, q->left);
}
bool isSymmetric(struct TreeNode* root){
if(root == NULL)
return true;
else
return func(root->left, root->right);
}
层序遍历(注意弹出操作)
def isSymmetric(root):
if not root: return True
que=[root]
len_que=len(que)
while que:
temp=[]
for _ in range(len_que):
node=que.pop(0) # key point
if node:
temp.append(node.val)
que.append(node.left)
que.append(node.right)
else:
temp.append(None)
if temp!=temp[::-1]: return False
len_que=len(que) # resize the length
return True
8 自上而下打印二叉树 I
二叉树的 广度优先搜索(BFS)BFS 通常借助 队列 的先入先出特性来实现。
例如:
给定二叉树: [3,9,20,null,null,15,7],
返回:[3,9,20,15,7]
思路:首先构建一个队列和一个数组,节点依次入队出队,出队的节点的值将会被保存到返回数组中
拿上面的例子来说,先将节点3入队,出队保存到数组,因为节点3的左右子树均不为空,将左右子树9,20入队,9出队,因为9的左右子树为空,20出队,接着将15,7入队…
#define MAX_NUM 2000
int *levelOrder(struct TreeNode *root, int *returnSize)
{
*returnSize = 0;
if (root == NULL) {
return NULL;
}
int *ret = (int *)malloc(sizeof(int) * MAX_NUM);
if (ret == NULL) {
return NULL;
}
struct TreeNode *queue[MAX_NUM];
int head = 0;
int tail = 0;
queue[tail++] = root;
while (head != tail) {
int last = tail;
while (head < last) {
struct TreeNode *cur = queue[head++];
ret[(*returnSize)++] = cur->val;
if (cur->left != NULL) {
queue[tail++] = cur->left;
}
if (cur->right != NULL) {
queue[tail++] = cur->right;
}
}
}
return ret;
}
class Solution:
def levelOrder(self, root: TreeNode) -> List[int]:
if not root: return []
res, queue = [], collections.deque()
queue.append(root)
while queue:
node = queue.popleft()
res.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
return res
9 自上而下打印二叉树 II
例如:
给定二叉树: [3,9,20,null,null,15,7],
返回:
[ [3], [9,20], [15,7] ]
思路:此题的返回数组要求是一个二维数组,思想和上一题是一样的,每次按层输出一个数组,C语言操作起来的确是复杂的很…
#define MAXSIZE 2000
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes)
{
if (root == NULL) {
*returnSize = 0;
return NULL;
}
struct TreeNode *queue[MAXSIZE] = {0};
int head = 0;
int tail = 0;
int **ret = (int**)malloc(sizeof(int*) * MAXSIZE);
if (ret == NULL) {
return NULL;
}
memset(ret, 0, sizeof(int*) * MAXSIZE);
*returnColumnSizes = (int*)malloc(sizeof(int*) * MAXSIZE);
if (*returnColumnSizes == NULL) {
return NULL;
}
memset(*returnColumnSizes, 0, sizeof(int*) * MAXSIZE);
queue[tail++] = root; //push
*returnSize = 0;
while (head < tail) {
int size = (tail - head + MAXSIZE) % MAXSIZE;
(*returnColumnSizes)[*returnSize] = size;
ret[*returnSize] = (int*)malloc(sizeof(int) * size);
for (int i = 0; i < size; i++) {
struct TreeNode *temp = queue[head++]; //pop
ret[*returnSize][i] = temp->val;
if (temp->left != NULL) {
queue[tail++] = temp->left;
}
if (temp->right != NULL) {
queue[tail++] = temp->right;
}
}
(*returnSize)++;
}
return ret;
}
class Solution(object):
def levelOrder(self, root):
que = [root]
len_que = len(que)
res = []
if not root: return res
while que:
tmp = []
for _ in range(len_que):
node = que.pop(0)
tmp.append(node.val)
if node.left: que.append(node.left)
if node.right: que.append(node.right)
len_que = len(que)
res.append(tmp)
return res
10 自上而下打印二叉树 III
要求在输出的时候,每偶数行逆序
思路:核心思想和前面两题是一样的,在实现上,只需要在第二题的基础上,判断是否是偶数行,如果是就逆序。
#define MAXSIZE 2000
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes)
{
if (root == NULL) {
*returnSize = 0;
return NULL;
}
struct TreeNode *queue[MAXSIZE] = {0};
int head = 0;
int tail = 0;
int **ret = (int**)malloc(sizeof(int*) * MAXSIZE);
if (ret == NULL) {
return NULL;
}
memset(ret, 0, sizeof(int*) * MAXSIZE);
*returnColumnSizes = (int*)malloc(sizeof(int*) * MAXSIZE);
if (*returnColumnSizes == NULL) {
return NULL;
}
memset(*returnColumnSizes, 0, sizeof(int*) * MAXSIZE);
queue[tail++] = root; //push
*returnSize = 0;
while (head < tail) {
int size = (tail - head + MAXSIZE) % MAXSIZE;
(*returnColumnSizes)[*returnSize] = size;
ret[*returnSize] = (int*)malloc(sizeof(int) * size);
for (int i = 0; i < size; i++) {
struct TreeNode *temp = queue[head++]; //pop
ret[*returnSize][i] = temp->val;
if (temp->left != NULL) {
queue[tail++] = temp->left;
}
if (temp->right != NULL) {
queue[tail++] = temp->right;
}
}
if((*returnSize) % 2 != 0){
for(int i = 0; i < size/2; i++){
int temp;
temp = ret[*returnSize][i];
ret[*returnSize][i] = ret[*returnSize][size-1-i];
ret[*returnSize][size-1-i] = temp;
}
}
(*returnSize)++;
}
return ret;
}
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
tmp, queue = [], collections.deque()
if not root: return tmp
queue.append(root)
len_que = len(queue)
k = 2
while queue:
res = []
for _ in range(len_que):
node = queue.popleft()
res.append(node.val)
if node.left: queue.append(node.left)
if node.right: queue.append(node.right)
tmp.append(res) if k%2==0 else tmp.append(res[::-1])
k += 1
len_que = len(queue)
return tmp
11 二叉搜索树的后序遍历序列
判断给定序列是否是二叉搜索树的后续遍历序列
思路:首先题目给的是二叉搜索树的条件,我们知道二叉搜索树的性质是,根节点、左子树、右子树的大小关系为 left < root < right,同时,后续遍历序列是 左右根 那么得到的序列的最后一个元素必然是根节点,那么我们从根节点往前找,前一小搓是左子树,他的值肯定是小于根节点的,我们就从前
bool verifyPostorder(int* postorder, int postorderSize){
if(postorderSize == 0 || postorderSize == 1)
return true;
int i,j;
for(i = 0; i < postorderSize - 1; i++){
if(postorder[i] > postorder[postorderSize-1])
break;
}
for(j = i; j < postorderSize - 1; j++){
if(postorder[j] < postorder[postorderSize-1])
return false;
}
return verifyPostorder(postorder, i) && verifyPostorder(&postorder[i], postorderSize-1-i);
}
class Solution:
def verifyPostorder(self, postorder: [int]) -> bool:
def recur(i, j):
if i >= j: return True
p = i
while postorder[p] < postorder[j]: p += 1
m = p
while postorder[p] > postorder[j]: p += 1
return p == j and recur(i, m - 1) and recur(m, j - 1)
return recur(0, len(postorder) - 1)
class Solution:
def verifyPostorder(self, postorder: List[int]) -> bool:
if not postorder: return True
index, n = 0, len(postorder)
while index < n and postorder[index] < postorder[-1]:
index += 1
for i in range(index, n-1):
if postorder[i] < postorder[-1]:
return False
return self.verifyPostorder(postorder[:index]) and self.verifyPostorder(postorder[index:n-1])
12 二叉树中和为某一值的路径
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
思路:考虑深度优先遍历,先序遍历按照根、左、右的顺序,遍历所有节点。
定义一个 dfs 函数,主要做如下工作:
路径更新:将当前节点值 root->val 加入路径 path
目标值更新:target - = root-val
路径记录:当 root 为叶节点(无子树)且路径和等于目标值时,将此路径 path 加入 res 中
先序遍历:递归左/右子节点
路径恢复:向上回溯前,需要将当前节点从路径 path 中删除
int** ret;
int retSize;
int* retColSize;
int* path;
int pathSize;
void dfs(struct TreeNode* root, int target) {
if (root == NULL) {
return;
}
path[pathSize++] = root->val;
target -= root->val;
if (root->left == NULL && root->right == NULL && target == 0) {
int* tmp = malloc(sizeof(int) * pathSize);
memcpy(tmp, path, sizeof(int) * pathSize);
ret[retSize] = tmp;
retColSize[retSize++] = pathSize;
}
dfs(root->left, target);
dfs(root->right, target);
pathSize--;
}
int** pathSum(struct TreeNode* root, int target, int* returnSize, int** returnColumnSizes) {
ret = malloc(sizeof(int*) * 2001);
retColSize = malloc(sizeof(int) * 2001);
path = malloc(sizeof(int) * 2001);
retSize = pathSize = 0;
dfs(root, target);
*returnColumnSizes = retColSize;
*returnSize = retSize;
return ret;
}
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
res, path = [], []
def recur(root, tar):
if not root: return
path.append(root.val)
tar -= root.val
if tar == 0 and not root.left and not root.right:
res.append(list(path))
recur(root.left, tar)
recur(root.right, tar)
path.pop()
recur(root, sum)
return res