二叉树的直径
二叉树的层序遍历
将有序数组转换为二叉搜索树
验证二叉搜索树
543. 二叉树的直径

/**
* 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 {
private int maxDiameter = 0;
public int diameterOfBinaryTree(TreeNode root) {
maxDiameter = 0;
depth(root);
return maxDiameter;
}
// 计算以 node 为根的子树深度,同时更新 maxDiameter
private int depth(TreeNode node) {
if (node == null) {
return 0;
}
int leftDepth = depth(node.left); // 左子树深度
int rightDepth = depth(node.right); // 右子树深度
// 更新最大直径:当前节点的直径 = leftDepth + rightDepth
maxDiameter = Math.max(maxDiameter, leftDepth + rightDepth);
// 返回当前节点的子树深度(取左右子树最大深度 +1)
return Math.max(leftDepth, rightDepth) + 1;
}
}
class Solution {
private int ans;
public int diameterOfBinaryTree(TreeNode root) {
dfs(root);
return ans;
}
private int dfs(TreeNode node) {
if (node == null) {
return -1; // 对于叶子来说,链长就是 -1+1=0
}
int lLen = dfs(node.left) + 1; // 左子树最大链长+1
int rLen = dfs(node.right) + 1; // 右子树最大链长+1
ans = Math.max(ans, lLen + rLen); // 两条链拼成路径
return Math.max(lLen, rLen); // 当前子树最大链长
}
}
作者:灵茶山艾府
链接:https://leetcode.cn/problems/diameter-of-binary-tree/solutions/2227017/shi-pin-che-di-zhang-wo-zhi-jing-dpcong-taqma/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解题思路:后序遍历(DFS)
直径 = 树中任意两节点之间最长路径的边数
路径可能经过根节点,也可能不经过
核心公式:对任意节点,以它为 "拐点" 的直径 = 左子树深度 + 右子树深度
102. 二叉树的层序遍历

/**
* 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> queue = new LinkedList<>();
queue.offer(root); // 根节点入队
while (!queue.isEmpty()) {
int levelSize = queue.size(); // 当前层的节点数
List<Integer> currentLevel = new ArrayList<>();
// 遍历当前层所有节点
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
currentLevel.add(node.val); // 记录当前节点值
// 左子节点非空则入队
if (node.left != null) {
queue.offer(node.left);
}
// 右子节点非空则入队
if (node.right != null) {
queue.offer(node.right);
}
}
res.add(currentLevel); // 将当前层结果加入总列表
}
return res;
}
}
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) {
return List.of();
}
List<List<Integer>> ans = new ArrayList<>();
Queue<TreeNode> q = new ArrayDeque<>();
q.add(root);
while (!q.isEmpty()) {
int n = q.size();
List<Integer> vals = new ArrayList<>(n); // 预分配空间
while (n-- > 0) {
TreeNode node = q.poll();
vals.add(node.val);
if (node.left != null) q.add(node.left);
if (node.right != null) q.add(node.right);
}
ans.add(vals);
}
return ans;
}
}
作者:灵茶山艾府
链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/solutions/2049807/bfs-wei-shi-yao-yao-yong-dui-lie-yi-ge-s-xlpz/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解题思路1:一个队列
-
队列初始化:将根节点入队,作为遍历起点。
-
层遍历循环:
-
每次循环开始时,队列中存放的是当前层的所有节点 ,用
levelSize记录该层节点数。 -
遍历当前层所有节点:
-
取出节点并将其值加入当前层列表。
-
将非空的左右子节点入队,作为下一层的待处理节点。
-
-
将当前层列表加入结果集,完成一层的处理。
-
边界处理 :空树直接返回空列表,单节点树返回
[[root.val]],符合题目要求。class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) {
return List.of();
}
List<List<Integer>> ans = new ArrayList<>();
List<TreeNode> cur = List.of(root);
while (!cur.isEmpty()) {
List<TreeNode> nxt = new ArrayList<>();
List<Integer> vals = new ArrayList<>(cur.size()); // 预分配空间
for (TreeNode node : cur) {
vals.add(node.val);
if (node.left != null) nxt.add(node.left);
if (node.right != null) nxt.add(node.right);
}
cur = nxt;
ans.add(vals);
}
return ans;
}
}作者:灵茶山艾府
链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/solutions/2049807/bfs-wei-shi-yao-yao-yong-dui-lie-yi-ge-s-xlpz/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解题思路2:两个数组
108. 将有序数组转换为二叉搜索树

/**
* 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 sortedArrayToBST(int[] nums) {
return build(nums, 0, nums.length - 1);
}
// 递归构建:在 [left, right] 区间内生成平衡 BST
private TreeNode build(int[] nums, int left, int right) {
// 终止条件:区间为空,返回 null
if (left > right) {
return null;
}
// 选择中间位置作为根节点(保证平衡)
int mid = left + (right - left) / 2; // 避免溢出
TreeNode node = new TreeNode(nums[mid]);
// 递归构建左子树(左半区间)
node.left = build(nums, left, mid - 1);
// 递归构建右子树(右半区间)
node.right = build(nums, mid + 1, right);
return node;
}
}
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return dfs(nums, 0, nums.length);
}
// 定义:把 nums[left ... right-1] 转成平衡二叉搜索树
private TreeNode dfs(int[] nums, int left, int right) {
// 区间为空,返回 null
if (left == right) {
return null;
}
// 无符号右移,等价于 (left+right)/2,但是不会溢出
int m = (left + right) >>> 1;
// 构造节点:
// 左孩子 = 左半区间 [left, m)
// 右孩子 = 右半区间 [m+1, right)
return new TreeNode(
nums[m],
dfs(nums, left, m),
dfs(nums, m + 1, right)
);
}
}
解题思路:递归分治法
区间划分:
-
left和right定义当前处理的数组区间。 -
当
left > right时,区间为空,返回null。
根节点选择:
-
取区间中点
mid作为根节点,使左右子树节点数尽可能相等,保证树的平衡。 -
用
left + (right - left) / 2替代(left + right) / 2,避免整数溢出。
递归 构建:
-
左子树:
[left, mid-1] -
右子树:
[mid+1, right] -
最终得到的树天然满足 BST 性质(左 < 根 < 右)且高度平衡。
98. 验证二叉搜索树

/**
* 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 isValidBST(TreeNode root) {
// 用 Long 避免边界值溢出(如 node.val = Integer.MIN_VALUE)
return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean isValidBST(TreeNode node, long low, long high) {
// 空节点天然合法
if (node == null) return true;
// 节点值不在区间内 → 不合法
if (node.val <= low || node.val >= high) return false;
// 递归校验左右子树
return isValidBST(node.left, low, node.val)
&& isValidBST(node.right, node.val, high);
}
}
解法思路1:递归法(约束范围)
思路:给每个节点规定一个取值区间 (low, high),节点值必须在这个区间内才合法。
-
根节点:
(-∞, +∞) -
左孩子:继承父节点的
low,上限为父节点值 -
右孩子:继承父节点的
high,下限为父节点值
解法 1: 前序遍历 ・区间约束法
每个节点必须在 (left, right) 区间内
-
左子树:上限 = 当前节点值
-
右子树:下限 = 当前节点值
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}private boolean isValidBST(TreeNode node, long left, long right) { if (node == null) { return true; } long x = node.val; return left < x && x < right && isValidBST(node.left, left, x) && isValidBST(node.right, x, right); }}
解法 2: 中序遍历 ・升序判断法
BST 中序遍历 一定是严格递增的
只要出现 当前值 ≤ 上一个值 就不是 BST
class Solution {
private long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
if (!isValidBST(root.left)) { // 左
return false;
}
if (root.val <= pre) { // 中
return false;
}
pre = root.val;
return isValidBST(root.right); // 右
}
}
解法 3: 后序遍历 ・子树最值法
返回每棵子树的 [最小值,最大值]
-
当前节点 > 左子树最大值
-
当前节点 < 右子树最小值满足才是 BST
class Solution {
public boolean isValidBST(TreeNode root) {
return dfs(root)[1] != Long.MAX_VALUE;
}private long[] dfs(TreeNode node) { if (node == null) { return new long[]{Long.MAX_VALUE, Long.MIN_VALUE}; } long[] left = dfs(node.left); long[] right = dfs(node.right); long x = node.val; // 也可以在递归完左子树之后立刻判断,如果发现不是二叉搜索树,就不用递归右子树了 if (x <= left[1] || x >= right[0]) { return new long[]{Long.MIN_VALUE, Long.MAX_VALUE}; } return new long[]{Math.min(left[0], x), Math.max(right[1], x)}; }}
解法思路2:前中后序遍历
总结
本文整理了四道二叉树高频经典题:二叉树直径通过后序 DFS 计算左右子树深度之和求得最长路径;层序遍历采用 BFS 队列或双列表实现按层遍历;有序数组转平衡 BST 使用递归分治,取中间节点为根保证平衡;验证二叉搜索树则可通过前序区间约束、中序递增判断、后序子树最值三种方法,利用 BST 严格有序特性完成校验。整体覆盖 DFS、BFS、递归分治与二叉搜索树核心性质,是二叉树基础题型的通用解题模板。
