- 二叉树的前序遍历
要掌握前中后序一种迭代的写法,面试的时候写出了递归,一般会进一步考察能不能写出相应的迭代。
模拟前中后序遍历的就用栈,如果是适合层序遍历就用队列,其他情况先用队列试试行不行,不行再用栈。
# 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 preorderTraversal(self, root: TreeNode) -> List[int]:
result = []
def traversal(root):
if root == None:
return
result.append(root.val)
traversal(root.left)
traversal(root.right)
traversal(root)
return result
# 方法二:迭代法
# 写法一:
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
stack = []
res = []
if root == None: return res
stack.append(root)
while stack:
cur = stack.pop()
res.append(cur.val)
if cur.right: # 先右后左,这样出栈的时候才是先返回左节点的值
stack.append(cur.right)
if cur.left:
stack.append(cur.left)
return res
# 写法二:
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
result = []
st = []
if root:
st.append(root)
while st:
node = st.pop()
if node != None:
if node.right: #右
st.append(node.right)
if node.left: #左
st.append(node.left)
st.append(node) #中
st.append(None)
else:
node = st.pop()
result.append(node.val)
return result
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
// 方法一:递归法
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
preOrder(root, result);
return result;
}
void preOrder(TreeNode root, List result) {
if (root == null) {
return;
}
result.add(root.val);
preOrder(root.left, result);
preOrder(root.right, result);
}
}
// 方法二:迭代法
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> st = new Stack<>();
if (root != null) st.push(root);
while (!st.empty()) {
TreeNode node = st.pop();
if (node != null) {
if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈)
if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈)
st.push(node); // 添加中节点
st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
} else { // 只有遇到空节点的时候,才将下一个节点放进结果集
node = st.pop();
result.add(node.val); // 加入到结果集
}
}
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 postorderTraversal(self, root: TreeNode) -> List[int]:
result = []
def traversal(root):
if root == None:
return
traversal(root.left)
traversal(root.right)
result.append(root.val)
traversal(root)
return result
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
postOrder(root, result);
return result;
}
void postOrder(TreeNode root, List result) {
if (root == null) {
return;
}
postOrder(root.left, result);
postOrder(root.right, result);
result.add(root.val);
}
}
# 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 inorderTraversal(self, root: TreeNode) -> List[int]:
result = []
def traversal(root):
if root == None:
return
traversal(root.left)
result.append(root.val)
traversal(root.right)
traversal(root)
return result
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
inOrder(root, result);
return result;
}
void inOrder(TreeNode root, List result) {
if (root == null) {
return;
}
inOrder(root.left, result);
result.add(root.val);
inOrder(root.right, result);
}
}
- 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],3 / \ 9 20 / \ 15 7
返回其层序遍历结果:
[ [3],
[9,20],
[15,7] ]
# 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]]:
res = []
if not root:
return res
# deque来自collections模块,不在力扣平台时,需要手动写入
# 'from collections import deque' 导入
# deque相比list的好处是,list的pop(0)是O(n)复杂度,deque的popleft()是O(1)复杂度
que = deque([root])
while que:
tmp = []
for i in range(len(que)): # 循环遍历当前层的节点,第一次只有root节点
cur = que.popleft() # 从队列左边弹出,故后面加入队列的顺序是先左后右
tmp.append(cur.val) # tmp数组存放当前层的所有元素
if cur.left: # 将下一层的节点依次加入队列中
que.append(cur.left)
if cur.right:
que.append(cur.right)
res.append(tmp) # 遍历完一层,将结果添加到res中
return res
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
List<Integer> tmp = new ArrayList<>();
int size = que.size();
for (int i = 0; i < size; i++) { // 这里用i<que.size()会出错,因为后面que.add会改变que的size,导致判断出错。
TreeNode cur = que.poll(); // poll: 移除并返问队列头部的元素
tmp.add(cur.val);
if (cur.left != null) {
que.add(cur.left);
}
if (cur.right != null) {
que.add(cur.right);
}
}
res.add(tmp);
}
return res;
}
}
给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
# 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: TreeNode) -> List[List[int]]:
res = []
if not root:
return res
que = deque([])
que.append(root)
while que:
tmp = []
for i in range(len(que)):
cur = que.popleft()
tmp.append(cur.val)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
res.append(tmp)
res.reverse()
return res
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
List<Integer> tmp = new ArrayList<>();
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode cur = que.poll();
tmp.add(cur.val);
if (cur.left != null) {
que.add(cur.left);
}
if (cur.right != null) {
que.add(cur.right);
}
}
res.add(tmp);
}
List<List<Integer>> resRever = new ArrayList<>();
for (int i = res.size() - 1; i >= 0; i--) {
resRever.add(res.get(i));
}
return resRever;
}
}
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例 1:
输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
# 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 rightSideView(self, root: TreeNode) -> List[int]:
res = []
if not root:
return res
que = deque([root])
while que:
res.append(que[-1].val)
for i in range(len(que)):
cur = que.popleft()
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
return res
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode cur = que.poll();
if (cur.left != null) {
que.add(cur.left);
}
if (cur.right != null) {
que.add(cur.right);
}
if (i == size - 1) {
res.add(cur.val);
}
}
}
return res;
}
}
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
示例 1:
输入:
3 / \ 9 20 / \ 15 7
输出:[3, 14.5, 11]
# 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 averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
res = []
if not root:
return res
que = deque([root])
while que:
size = len(que)
sum = 0
for i in range(size):
cur = que.popleft()
sum += cur.val
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
res.append(sum/size) # //表示整数除法;/表示浮点数除法(返回小数)
return res
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
int size = que.size();
double sum = 0;
for (int i = 0; i < size; i++) {
TreeNode cur = que.poll();
sum += cur.val;
if (cur.left != null) {
que.add(cur.left);
}
if (cur.right != null) {
que.add(cur.right);
}
}
res.add(sum / size);
}
return res;
}
}
给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。
示例 1:
输入:root = [1,null,3,2,4,null,5,6]
输出:[[1],[3,2,4],[5,6]]
# python
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
res = []
if not root:
return res
que = deque([root])
while que:
level = []
for i in range(len(que)):
cur = que.popleft()
level.append(cur.val)
# cur.children 是 Node 对象组成的列表,也可能为 None
if cur.children:
que.extend(cur.children)
res.append(level)
return res
// Java
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<Node> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
List<Integer> level = new ArrayList<>();
int size = que.size();
for (int i = 0; i < size; i++) {
Node cur = que.poll();
level.add(cur.val);
if (cur.children != null) {
que.addAll(cur.children);
}
}
res.add(level);
}
return res;
}
}
给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。
示例1:
输入: root = [1,3,2,5,3,null,9]
输出: [1,3,9]
解释:1 / \ 3 2 / \ \ 5 3 9
# 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 largestValues(self, root: TreeNode) -> List[int]:
res = []
if not root:
return res
que = deque([root])
while que:
level = []
for i in range(len(que)):
cur = que.popleft()
level.append(cur.val)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
res.append(max(level))
return res
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
List<Integer> level = new ArrayList<>();
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode cur = que.poll();
level.add(cur.val);
if (cur.left != null) {
que.add(cur.left);
}
if (cur.right != null) {
que.add(cur.right);
}
}
res.add(Collections.max(level));
}
return res;
}
}
示例:
输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,‘#’ 标志着每一层的结束。
# python
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return # return None
que = deque([root])
while que:
n = len(que)
for i in range(n):
cur = que.popleft() # cur = que.pop(0)
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
if i == n - 1:
break
cur.next = que[0]
return root
// Java
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
if (root == null) {
return null;
}
Queue<Node> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
Node cur = que.poll();
if (cur.left != null) {
que.add(cur.left);
}
if (cur.right != null) {
que.add(cur.right);
}
if (i == size - 1) {
break;
}
cur.next = que.peek(); // 返回队头元素但不删除
}
}
return root;
}
}
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],3 / \ 9 20 / \ 15 7
返回它的最大深度 3 。
# 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 maxDepth(self, root: TreeNode) -> int:
depth = 0
if not root:
return 0
que = deque([root])
while que:
for i in range(len(que)):
cur = que.popleft()
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
depth += 1
return depth
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int depth = 0;
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode cur = que.poll();
if (cur.left != null) {
que.add(cur.left);
}
if (cur.right != null) {
que.add(cur.right);
}
}
depth++;
}
return depth;
}
}
相关题目:N叉数的最大深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:2
# 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 minDepth(self, root: TreeNode) -> int:
if not root:
return 0
que = deque([root])
depth = 0
while que:
depth += 1
for i in range(len(que)):
cur = que.popleft()
if cur.left == None and cur.right == None: # 如果当前节点的左右孩子都为空,直接返回最小深度
return depth
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
return depth
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int minDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
int depth = 0;
while (!que.isEmpty()) {
int size = que.size();
depth++;
for (int i = 0; i < size; i++) {
TreeNode cur = que.poll();
if (cur.left == null && cur.right == null) {
return depth;
}
if (cur.left != null) {
que.add(cur.left);
}
if (cur.right != null) {
que.add(cur.right);
}
}
}
return depth;
}
}
翻转一棵二叉树。
示例:
输入:
4 / \ 2 7 / \ / \ 1 3 6 9
输出:
4 / \ 7 2 / \ / \ 9 6 3 1
# 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:
# 1. 确定递归函数的参数和返回值
def invertTree(self, root: TreeNode) -> TreeNode:
# 2. 确定终止条件
if not root:
return None
# 3. 确定单层递归的逻辑
root.left, root.right = root.right, root.left # 中
self.invertTree(root.left) # 左
self.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:
if not root:
return root
que = deque([root])
while que:
for i in range(len(que)):
cur = que.popleft()
if cur.right:
que.append(cur.right)
if cur.left:
que.append(cur.left)
cur.left, cur.right = cur.right, cur.left
return root
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
//DFS递归
class Solution {
/**
* 前后序遍历都可以
* 中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换)
*/
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
swapChildren(root);
invertTree(root.left);
invertTree(root.right);
return root;
}
private void swapChildren(TreeNode root) {
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
给定一个 n
叉树的根节点 root
,返回 其节点值的 前序遍历 。
n 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。
示例 1:
输入:root = [1,null,3,2,4,null,5,6]
输出:[1,3,5,6,2,4]
# python
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def preorder(self, root: 'Node') -> List[int]:
res = []
if not root:
return res
def traversal(root):
res.append(root.val)
for child in root.children:
traversal(child)
traversal(root)
return res
// Java
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<Integer> preorder(Node root) {
List<Integer> res = new ArrayList<>();
traversal(root, res);
return res;
}
private void traversal(Node root, List res) {
if (root == null) return;
res.add(root.val);
for (Node child : root.children) {
traversal(child, res);
}
}
}
# python
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def postorder(self, root: 'Node') -> List[int]:
res = []
def traversal(root):
if not root:
return
for child in root.children:
traversal(child)
res.append(root.val)
traversal(root)
return res
// Java
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<Integer> postorder(Node root) {
List<Integer> res = new ArrayList<>();
traversal(root, res);
return res;
}
private void traversal(Node root, List res) {
if (root == null) return;
for (Node child : root.children) {
traversal(child, res);
}
res.add(root.val);
}
}
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1 / \ 2 2 / \ / \ 3 4 4 3
进阶:
你可以运用递归和迭代两种方法解决这个问题吗?
# 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 isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
return self.compare(root.left, root.right)
def compare(self, left, right):
if not left and not right: # 左节点为空、右节点为空,此时说明是对称的
return True
elif not left or not right or left.val != right.val: # 左右一个节点不为空,或者都不为空但数值不相同,返回False
return False
outside = self.compare(left.left, right.right) # 比较外侧是否相等
inside = self.compare(left.right, right.left) # 比较内侧是否相等
return outside and inside
# 方法二:迭代法
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
que = deque([root.left, root.right]) # 将左右子树的头结点加入队列
while que: # 接下来就要判断这这两个树是否相互翻转
left = que.popleft()
right = que.popleft()
if not left and not right: # 左节点为空、右节点为空,此时说明是对称的
# return True # 继续判断其他侧的左右节点,所以这里不能直接return True
continue
elif not left or not right or left.val != right.val: # 左右一个节点不为空,或者都不为空但数值不相同,返回False
return False
que.append(left.left) # 加入左节点左孩子
que.append(right.right) # 加入右节点右孩子
que.append(left.right) # 加入左节点右孩子
que.append(right.left) # 加入右节点左孩子
return True
// Java
// 方法一:递归法
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return compare(root.left, root.right);
}
private boolean compare(TreeNode left, TreeNode right) {
if (left == null && right == null) { // 左节点为空、右节点为空,此时说明是对称的
return true;
} else if (left == null || right == null || left.val != right.val) { // 左右一个节点不为空,或者都不为空但数值不相同,返回false
return false;
}
boolean outside = compare(left.left, right.right); // 比较外侧是否相等
boolean inside = compare(left.right, right.left); // 比较内侧是否相等
return outside && inside;
}
}
// 方法二:迭代法
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
Queue<TreeNode> que = new LinkedList<>();
que.add(root.left); // 将左子树头结点加入队列
que.add(root.right); // 将右子树头结点加入队列
while (!que.isEmpty()) { // 接下来就要判断这两个树是否相互翻转
TreeNode left = que.poll();
TreeNode right = que.poll();
if (left == null && right == null) { // 左节点为空、右节点为空,此时说明是对称的
continue;
} else if (left == null || right == null || left.val != right.val) { // 左右一个节点不为空,或者都不为空但数值不相同,返回false
return false;
}
que.add(left.left); // 加入左节点左孩子
que.add(right.right); // 加入右节点右孩子
que.add(left.right); // 加入左节点右孩子
que.add(right.left); // 加入右节点左孩子
}
return true;
}
}
将两棵二叉树的根节点当成前面的左右节点解法一模一样,跟翻转二叉树不同的是,每次比较的是左右子树的同一侧。
# python
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
que = deque([p, q])
while que:
left = que.popleft()
right = que.popleft()
if not left and not right:
continue # 递归法左右两边都为空,内侧或外侧就可以返回True了,但迭代法每次比较的是一对,得continue继续判断
elif not left or not right or left.val != right.val:
return False
que.append(left.left) # 与翻转二叉树不同,左右节点取的子节点是同一边
que.append(right.left)
que.append(left.right)
que.append(right.right)
return True
// Java
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
Queue<TreeNode> que = new LinkedList<>();
que.add(p);
que.add(q);
while (!que.isEmpty()) {
TreeNode left = que.poll();
TreeNode right = que.poll();
if (left == null && right == null) {
continue;
} else if (left == null || right == null || left.val != right.val) {
return false;
}
que.add(left.left);
que.add(right.left);
que.add(left.right);
que.add(right.right);
}
return true;
}
}
这道题可以直接利用上面的相同的树的代码,层序遍历第一棵树,取出每个节点和另一个树的根节点比较,是否是同一棵树。
# python
class Solution:
def isSubtree(self, root: TreeNode, subRoot: TreeNode) -> bool:
que = deque([root])
while que:
cur = que.popleft()
if self.isSameTree(cur, subRoot):
return True
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
return False
// Java
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
TreeNode cur = que.poll();
if (isSameTree(cur, subRoot)) {
return true;
}
if (cur.left != null) que.add(cur.left);
if (cur.right != null) que.add(cur.right);
}
return false;
}
}
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1~ 2h
个节点。
# 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 countNodes(self, root: TreeNode) -> int:
if not root:
return 0
count = 0
que = deque([root])
while que:
for i in range(len(que)):
cur = que.popleft()
count += 1
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
return count
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int countNodes(TreeNode root) {
if (root == null) return 0;
int count = 0;
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode cur = que.poll();
count++;
if (cur.left != null) que.add(cur.left);
if (cur.right != null) que.add(cur.right);
}
}
return count;
}
}
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
# 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 isBalanced(self, root: TreeNode) -> bool:
if self.getHeight(root) == -1:
return False
else:
return True
def getHeight(self, root):
if not root:
return 0
if (leftHeight := self.getHeight(root.left)) == -1:
return -1
if (rightHeight := self.getHeight(root.right)) == -1:
return -1
if abs(leftHeight - rightHeight) > 1:
return -1
else:
return 1 + max(leftHeight, rightHeight)
# 等同于下面写法
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def getHeight(root):
if not root:
return 0
left = getHeight(root.left)
right = getHeight(root.right)
if left == -1:
return -1
if right == -1:
return -1
if abs(left - right) > 1:
return -1
return 1 + max(left, right)
if getHeight(root) == -1:
return False
else:
return True
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
return getHeight(root) != -1;
}
private int getHeight(TreeNode root) {
if (root == null) return 0;
int left = getHeight(root.left);
int right = getHeight(root.right);
if (left == -1) return -1;
if (right == -1) return -1;
// 左右子树高度差大于1,return -1表示已经不是平衡树了
if (Math.abs(left - right) > 1) {
return -1;
} else {
return 1 + Math.max(left, right);
}
}
}
此题递归方式是一定要掌握的。此外可用迭代法,但效率很低,因为没有很好的模拟回溯的过程,所以有很多重复的计算。虽然理论上所有的递归都可以用迭代来实现,但是有的场景难度可能比较大。
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3,null,5]
输出:[“1->2->5”,“1->3”]
# 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 binaryTreePaths(self, root: TreeNode) -> List[str]:
path = ''
res = []
if not root:
return res
self.traversal(root, path, res)
return res
def traversal(self, root, path, res):
path += str(root.val)
# 若当前节点为叶子节点,直接输出
if not root.left and not root.right:
res.append(path)
if root.left:
# + '->' 是隐藏回溯,先递归左节点,结束左节点的递归后,cur节点仍是root,path回溯到原来root节点的path,再接着递归右节点。
self.traversal(root.left, path + '->', res)
if root.right:
self.traversal(root.right, path + '->', res)
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
// 方法一:递归+回溯
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
StringBuilder path = new StringBuilder();
List<String> res = new ArrayList<>();
traversal(root, path, res);
return res;
}
private void traversal(TreeNode root, StringBuilder path, List res) {
path.append(root.val);
// 若当前节点为叶子节点,直接输出
if (root.left == null && root.right == null) {
res.add(path.toString());
}
// 隐藏回溯,先递归左节点,结束左节点的递归后,cur节点仍是root,path回溯到原来root节点的path,再接着递归右节点。
if (root.left != null) {
StringBuilder pathLeft = new StringBuilder(path);
traversal(root.left, pathLeft.append("->"), res);
}
if (root.right != null) {
StringBuilder pathRight = new StringBuilder(path);
traversal(root.right, pathRight.append("->"), res);
}
}
}
计算给定二叉树的所有左叶子之和。
示例:
3 / \ 9 20 / \ 15 7
在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
# 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 sumOfLeftLeaves(self, root: TreeNode) -> int:
if not root:
return 0
# 判断根节点的左节点是否为左叶子,没有左叶子则结果增加0
cur_val = 0
if (root.left != None and root.left.left == None and root.left.right == None):
cur_val = root.left.val
# 递归找左右子树的左叶子
left_val = self.sumOfLeftLeaves(root.left)
right_val = self.sumOfLeftLeaves(root.right)
return cur_val + left_val + right_val
# 方法二:迭代法
class Solution:
def sumOfLeftLeaves(self, root: TreeNode) -> int:
res = 0
if not root:
return res
stack = []
stack.append(root)
while stack:
cur = stack.pop()
if (cur.left != None and cur.left.left == None and cur.left.right == None):
res += cur.left.val
if cur.left:
stack.append(cur.left)
if cur.right:
stack.append(cur.right)
return res
// Java
// 方法一:递归法
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) return 0;
int curValue = 0;
if (root.left != null && root.left.left == null && root.left.right == null) {
curValue = root.left.val;
}
int leftValue = sumOfLeftLeaves(root.left);
int rightValue = sumOfLeftLeaves(root.right);
return curValue + leftValue + rightValue;
}
}
// 方法二:迭代法
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
int res = 0;
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.add(root);
while (!stack.isEmpty()) {
TreeNode cur = stack.pop();
if (cur.left != null && cur.left.left == null && cur.left.right == null) {
res += cur.left.val;
}
if (cur.left != null) stack.add(cur.left);
if (cur.right != null) stack.add(cur.right);
}
return res;
}
}
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
示例 2:
输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7
# 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 findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
# 层序遍历找最后一行的第一个节点就是树左下角的值
res = 0
if not root:
return None
que = deque([root])
while que:
for i in range(len(que)):
if i == 0:
res = que[i].val
cur = que.popleft()
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
return res
// Java
class Solution {
public int findBottomLeftValue(TreeNode root) {
int res = 0;
Queue<TreeNode> que = new LinkedList<>();
que.add(root);
while (!que.isEmpty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode cur = que.poll();
if (i == 0) res = cur.val;
if (cur.left != null) que.add(cur.left);
if (cur.right != null) que.add(cur.right);
}
}
return res;
}
}
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
此题不需要遍历整棵树,所以递归函数需要返回值。
# 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 hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root: # 别忘记处理空treenode
return False
return self.isornot(root, targetSum - root.val)
def isornot(self, root, targetSum):
if not root.left and not root.right and targetSum == 0: # 遇到叶子节点,并且计数为0
return True
if not root.left and not root.right: # 遇到叶子节点,计数不为0
return False
if root.left:
targetSum -= root.left.val
if self.isornot(root.left, targetSum): return True # 递归,处理左节点
targetSum += root.left.val # 回溯
if root.right:
targetSum -= root.right.val
if self.isornot(root.right, targetSum): return True # 递归,处理右节点
targetSum += root.right.val # 回溯
return False
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) return false;
targetSum -= root.val;
// if (root.left == null && root.right == null && targetSum == 0) return true;
// if (root.left == null && root.right == null) return false;
if (root.left == null && root.right == null) return targetSum == 0;
if (root.left != null) {
boolean left = hasPathSum(root.left, targetSum);
if (left) return true;
targetSum += root.left.val;
}
if (root.right != null) {
boolean right = hasPathSum(root.right, targetSum);
if (right) return true;
targetSum += root.right.val;
}
return false;
}
}
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
此题需要遍历整棵树,所以递归函数不需要返回值。
# 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 pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
def traversal(cur, remain):
if not cur.left and not cur.right:
if remain == 0:
result.append(path[:])
return
if cur.left:
remain -= cur.left.val
path.append(cur.left.val)
traversal(cur.left, remain)
path.pop()
remain += cur.left.val
if cur.right:
remain -= cur.right.val
path.append(cur.right.val)
traversal(cur.right, remain)
path.pop()
remain += cur.right.val
result, path = [], []
if not root:
return []
path.append(root.val)
remain = targetSum - root.val
traversal(root, remain)
return result
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
List<List<Integer>> result;
LinkedList<Integer> path;
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
result = new LinkedList<>();
path = new LinkedList<>();
if (root == null) return result;
int remain = targetSum - root.val;
path.add(root.val);
traversal(root, remain);
return result;
}
private void traversal(TreeNode root, int remain) {
if (root.left == null && root.right == null) {
if (remain == 0) {
// 错误写法:result.add(path);
result.add(new LinkedList<>(path));
}
return;
}
if (root.left != null) {
remain -= root.left.val;
path.offer(root.left.val);
traversal(root.left, remain);
path.removeLast();
remain += root.left.val;
}
if (root.right != null) {
remain -= root.right.val;
path.offer(root.right.val);
traversal(root.right, remain);
path.removeLast();
remain += root.right.val;
}
}
}
给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。
示例 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
# 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 buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
# 第一步: 特殊情况讨论: 树为空. (递归终止条件)
if not preorder:
return None
# 第二步: 前序遍历的第一个就是当前的中间节点.
root_val = preorder[0]
root = TreeNode(root_val)
# 第三步: 找切割点.
index = inorder.index(root_val)
# 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
inorder_left = inorder[:index]
inorder_right = inorder[index + 1:]
# 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
preorder_left = preorder[1 : 1 + len(inorder_left)]
preorder_right = preorder[1 + len(inorder_left):]
# 第六步: 递归
root.left = self.buildTree(preorder_left,inorder_left)
root.right = self.buildTree(preorder_right,inorder_right)
return root
// Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return helper(preorder, inorder);
}
public TreeNode helper(int[] preorder, int[] inorder) {
// if (preorder == null || preorder.length == 0) return null;
if (preorder.length == 0) return null;
int rootVal = preorder[0];
TreeNode root = new TreeNode(rootVal);
int idx = 0;
for (int i = 0; i < inorder.length; i++) {
if (inorder[i] == rootVal){
idx = i;
break;
}
}
int[] inorderLeft = Arrays.copyOf(inorder, idx);
int[] inorderRight = Arrays.copyOfRange(inorder, idx + 1, inorder.length);
int[] preorderLeft = Arrays.copyOfRange(preorder, 1, inorderLeft.length + 1);
int[] preorderRight = Arrays.copyOfRange(preorder, 1 + inorderLeft.length, preorder.length);
root.left = helper(preorderLeft, inorderLeft);
root.right = helper(preorderRight, inorderRight);
return root;
}
}
# python
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
if not postorder:
return None
root_val = postorder[-1]
root = TreeNode(root_val)
idx = inorder.index(root_val)
inorder_left = inorder[:idx]
inorder_right = inorder[idx + 1:]
postorder_left = postorder[:len(inorder_left)]
postorder_right = postorder[len(inorder_left):-1]
root.left = self.buildTree(inorder_left, postorder_left)
root.right = self.buildTree(inorder_right, postorder_right)
return root
// Java
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return helper(inorder, postorder);
}
private TreeNode helper(int[] inorder, int[] postorder) {
if (postorder.length == 0) return null;
int rootVal = postorder[postorder.length - 1];
TreeNode root = new TreeNode(rootVal);
int idx = 0;
for (int i = 0; i < inorder.length; i++) {
if (inorder[i] == rootVal) {
idx = i;
break;
}
}
int[] inorderLeft = Arrays.copyOf(inorder, idx);
int[] inorderRight = Arrays.copyOfRange(inorder, idx + 1, inorder.length);
int[] postorderLeft = Arrays.copyOf(postorder, inorderLeft.length);
int[] postorderRight = Arrays.copyOfRange(postorder, inorderLeft.length, postorder.length - 1);
root.left = helper(inorderLeft, postorderLeft);
root.right = helper(inorderRight, postorderRight);
return root;
}
}
给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:
二叉树的根是数组 nums 中的最大元素。
左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 nums 构建的 最大二叉树 。
示例 1:
输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
# 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 constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
if not nums:
return None
max_value = max(nums)
max_index = nums.index(max_value)
root = TreeNode(max_value)
left = nums[:max_index]
right = nums[max_index + 1:]
root.left = self.constructMaximumBinaryTree(left)
root.right = self.constructMaximumBinaryTree(right)
return root
// Java
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return constructMaximumBinaryTree1(nums, 0, nums.length);
}
private TreeNode constructMaximumBinaryTree1(int[] nums, int left, int right) {
// if (nums == null || nums.length == 0) return null; 用索引的方式结束方式不能看nums,优点是不用建新的数组
if (right - left < 1) return null;
int maxIdx = left;
int maxVal = nums[left];
for (int i = left + 1; i < right; i++) {
if (nums[i] > maxVal) {
maxVal = nums[i];
maxIdx = i;
}
}
TreeNode root = new TreeNode(maxVal);
root.left = constructMaximumBinaryTree1(nums, left, maxIdx);
root.right = constructMaximumBinaryTree1(nums, maxIdx + 1, right);
return root;
}
}
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
# 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 mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
# 递归终止条件: 有一个节点为空, 则返回另外一个. 如果另一个也为None就直接返回None.
if not root1:
return root2
if not root2:
return root1
# 上面的递归终止条件保证了代码执行到这里root1, root2都非空.
root1.val += root2.val # 中
root1.left = self.mergeTrees(root1.left, root2.left) # 左
root1.right = self.mergeTrees(root1.right, root2.right) # 右
return root1 # 我们重复使用了题目给出的节点而不是创建新节点. 节省时间, 空间.
// Java
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) return root2;
if (root2 == null) return root1;
root1.val += root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
return root1;
}
}
给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
例如,
给定二叉搜索树:
4 / \ 2 7 / \ 1 3
和值: 2
你应该返回如下子树:2 / \ 1 3
在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。
二叉搜索树是一个有序树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉搜索树
# python
# 方法一:递归法
class Solution:
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
# 为什么要有返回值:
# 因为搜索到目标节点就要立即return,
# 这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。
if not root or root.val == val:
return root
if root.val > val:
return self.searchBST(root.left, val)
if root.val < val:
return self.searchBST(root.right, val)
# 方法二:迭代法
class Solution:
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
while root is not None:
if root.val > val:
root = root.left
elif root.val < val:
root = root.right
else: return root
return root # null
// Java
// 方法一:递归法
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if (root == null || root.val == val) return root;
if (root.val > val) {
return searchBST(root.left, val);
}
if (root.val < val) {
return searchBST(root.right, val);
}
return null;
}
}
// 方法二:迭代法
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
while (root != null) {
if (root.val > val) {
root = root.left;
} else if (root.val < val) {
root = root.right;
} else {
return root;
}
}
return root;
}
}
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
# python
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
# 规律: BST的中序遍历节点数值是从小到大.
max = None
# 递归
def isValidBST1(root):
nonlocal max
if not root:
return True
# 左
left = isValidBST1(root.left)
if not left: # 如果左边不是BST,直接返回False
return False
# 中
if max and max.val >= root.val: # 前面有节点的值大于当前节点节点返回False
return False
max = root
#右
right = isValidBST1(root.right)
return right
return isValidBST1(root)
// Java
class Solution {
TreeNode max = null;
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
// 左
boolean left = isValidBST(root.left);
if (left == false) return false;
// 中
if (max != null && max.val >= root.val) { // 注意要大于等于,搜索树里不能有相同元素
return false;
}
max = root;
// 右
boolean right = isValidBST(root.right);
return right;
}
}
给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
# python
class Solution:
def getMinimumDifference(self, root: TreeNode) -> int:
res = []
r = float("inf")
def createList(root): # 把二叉搜索树转换成有序数组
if not root:
return
createList(root.left)
res.append(root.val)
createList(root.right)
createList(root)
for i in range(len(res) - 1): # 统计有序数组的最小差值
r = min(abs(res[i] - res[i + 1]), r)
return r
// Java
class Solution {
public int getMinimumDifference(TreeNode root) {
ArrayList<Integer> list = new ArrayList();
int r = Integer.MAX_VALUE;
creatList(root, list);
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i + 1) - list.get(i) < r) {
r = list.get(i + 1) - list.get(i);
}
}
return r;
}
private ArrayList creatList(TreeNode root, ArrayList list) {
if (root == null) return null;
creatList(root.left, list);
list.add(root.val);
creatList(root.right, list);
return list;
}
}
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
# python
class Solution:
def __init__(self):
self.count, self.maxCount = 0, 0 # 统计频率,最大频率
# 用pre和cur两个指针指向前一元素与当前元素,比较是否相等,统计频率
self.res = []
self.pre = TreeNode()
def findMode(self, root: TreeNode) -> List[int]:
self.searchBST(root)
return self.res
def searchBST(self, root):
if not root: return
cur = root
self.searchBST(root.left)
# 第一个节点
if self.pre == None: # 前面没出现过,刚出现频率为1
self.count = 1
# 与前一个节点数值相同
elif self.pre.val == cur.val:
self.count += 1 # 前面出现的频率再+1
# 与前一个节点数值不相同
else:
self.count = 1 # 出现不相等值,频率再次从1开始
if self.count == self.maxCount:
self.res.append(cur.val) # 如果还有频率一样的众数,暂存到结果集
elif self.count > self.maxCount: # 一旦有比之前频率高的,之前的结果作废
self.maxCount = self.count # 更新最大频率
self.res.clear() # 清空self.res,确保res之前的的元素都失效
self.res.append(cur.val) # 将前面的最大出现频率的值暂存到结果集
self.pre = cur
self.searchBST(root.right)
// Java
class Solution {
int count = 0;
int maxCount = 0;
TreeNode pre = new TreeNode();
List<Integer> res = new ArrayList<>();
public int[] findMode(TreeNode root) {
searchBST(root);
// int[] result = res.stream().mapToInt(Integer::intValue).toArray();
int[] result = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
result[i] = res.get(i);
}
return result;
}
private void searchBST(TreeNode cur) {
if (cur == null) return;
searchBST(cur.left);
if (pre == null) {
count = 1;
} else if (pre.val == cur.val) {
count += 1;
} else {
count = 1;
}
if (count == maxCount) {
res.add(cur.val);
} else if (count > maxCount) {
maxCount = count;
res.clear();
res.add(cur.val);
}
pre = cur;
searchBST(cur.right);
}
}
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
# python
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or 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: # 左右子树分别找到了,说明此时的root就是要求的结果
return root
elif not left:
return right
else:
return left
// Java
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) return root; // 左右子树分别找到了,说明此时的root就是要求的结果
else if (left == null) return right;
else return left;
}
}
如果二叉树是二叉搜索树,则可以利用二叉搜索树的性质简化代码。
# python
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root.val > p.val and root.val > q.val: # p,q都在左侧
return self.lowestCommonAncestor(root.left, p, q)
if root.val < p.val and root.val < q.val: # p,q都在右侧
return self.lowestCommonAncestor(root.right, p, q)
return root # root在[p,q]区间中
// Java
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root.val > p.val && root.val > q.val) {
return lowestCommonAncestor(root.left, p, q);
}
if (root.val < p.val && root.val < q.val) {
return lowestCommonAncestor(root.right, p, q);
}
return root;
}
}
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
# python
class Solution:
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return TreeNode(val)
if val < root.val:
# 将val插入至当前root的左子树中合适的位置
# 并更新当前root的左子树为包含目标val的新左子树
root.left = self.insertIntoBST(root.left, val)
if val > root.val:
# 将val插入至当前root的右子树中合适的位置
# 并更新当前root的右子树为包含目标val的新右子树
root.right = self.insertIntoBST(root.right, val)
# 返回更新后的以当前root为根节点的新树
return root
// Java
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) return new TreeNode(val); // 如果当前节点为空,也就意味着val找到了合适的位置,此时创建节点直接返回。
if (val < root.val) {
root.left = insertIntoBST(root.left, val); // 递归创建左子树
} else if (val > root.val) {
root.right = insertIntoBST(root.right, val); // 递归创建右子树
}
return root;
}
}
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
# python
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root: return root # 第一种情况:没找到删除的节点,遍历到空节点直接返回了
if root.val == key:
if not root.left and not root.right: # 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回None为根节点
del root
return None
if not root.left and root.right: # 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
root = root.right
return root
if root.left and not root.right: # 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
root = root.left
return root
if root.left and root.right: # 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
v = root.right
while v.left:
v = v.left
v.left = root.left
root = root.right
return root
else:
if root.val > key: root.left = self.deleteNode(root.left, key) # 左递归
if root.val < key: root.right = self.deleteNode(root.right, key) # 右递归
return root
// Java
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null;
if (root.val == key) {
if (root.left == null) return root.right;
else if (root.right == null) return root.left;
else {
TreeNode tmp = root.right;
while (tmp.left != null) {
tmp = tmp.left;
}
tmp.left = root.left;
root = root.right;
return root;
}
} else if (root.val > key) {
root.left = deleteNode(root.left, key);
} else {
root.right = deleteNode(root.right, key);
}
return root;
}
}
37.修剪二叉搜索树
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树不应该改变保留在树中的元素的相对结构(即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在唯一的答案。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
# python
class Solution:
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
if not root:
return None
if root.val < low:
return self.trimBST(root.right, low, high) # 寻找符合区间[low, high]的节点
elif root.val > high:
return self.trimBST(root.left, low, high) # 寻找符合区间[low, high]的节点
else:
root.left = self.trimBST(root.left, low, high) # root->left接入符合条件的左孩子
root.right = self.trimBST(root.right, low, high) # root->right接入符合条件的右孩子
return root
// Java
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) return null;
if (root.val < low) {
return trimBST(root.right, low, high); // 寻找符合区间[low, high]的节点
} else if (root.val > high) {
return trimBST(root.left, low, high); // 寻找符合区间[low, high]的节点
} else {
root.left = trimBST(root.left, low, high); // root->left接入符合条件的左孩子
root.right = trimBST(root.right, low, high); // root->right接入符合条件的右孩子
}
return root;
}
}
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
# python
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
root = self.traversal(nums, 0, len(nums) - 1)
return root
def traversal(self, nums, left, right):
if left > right:
return None
# 确定左右界的中心,防越界
mid = left + (right - left) // 2
# 构建根节点
root = TreeNode(nums[mid])
# 构建以左右界的中心为分割点的左右子树
root.left = self.traversal(nums, left, mid - 1)
root.right = self.traversal(nums, mid + 1, right)
# 返回由被传入的左右界定义的某子树的根节点
return root
// Java
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
TreeNode root = traversal(nums, 0, nums.length - 1);
return root;
}
private TreeNode traversal(int[] nums, int left, int right) {
if (left > right) return null;
int mid = left + ((right - left) >> 1);
TreeNode root = new TreeNode(nums[mid]);
root.left = traversal(nums, left, mid - 1);
root.right = traversal(nums, mid + 1, right);
return root;
}
}
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
示例1:
输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
# python
class Solution:
def __init__(self):
self.pre = 0
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
# 倒序累加替换:
# [2, 5, 13] -> [20, 18, 13]
self.traversal(root)
return root
def traversal(self, root):
# 因为要遍历整棵树,所以递归函数不需要返回值
if not root:
return None
# 单层递归逻辑:中序遍历的反译 - 右中左
self.traversal(root.right) # 右
# 中节点:用当前root的值加上pre的值
root.val += self.pre # 中
self.pre = root.val
self.traversal(root.left) # 左
// Java
class Solution {
int pre;
public TreeNode convertBST(TreeNode root) {
traversal(root);
return root;
}
// 按右中左顺序遍历,累加即可
private void traversal(TreeNode root) {
if (root == null) {
return;
}
traversal(root.right);
root.val += pre;
pre = root.val;
traversal(root.left);
}
}