6 篇文章 0 订阅

二叉树

1. 144. 二叉树的前序遍历

问题

输入：root = [1,null,2,3]



输入：root = []



输入：root = [1]



输入：root = [1,2]



输入：root = [1,null,2]



• 树中节点数目在范围 [0, 100]
• -100 <= Node.val <= 100

代码

• 迭代法
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root != null)
stack.push(root);
while(!stack.empty()) {
TreeNode cur = stack.pop();
if(cur.right != null) stack.push(cur.right);
if(cur.left != null) stack.push(cur.left);
}
return res;
}
}

• 递归法
class Solution {
private List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
traversal(root);
return res;
}
private void traversal(TreeNode root) {
if(root == null) {
return;
}
preorderTraversal(root.left);
preorderTraversal(root.right);
}
}

• 统一迭代法
// 空指针来标记 已访问的节点
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root == null) {
return res;
}
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.peek();
if(node != null) {
stack.pop();
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
stack.push(node);
stack.push(null);
} else {
stack.pop();
node = stack.pop();
}
}
return res;
}
}


2. 94. 二叉树的中序遍历

问题

输入：root = [1,null,2,3]



输入：root = []



输入：root = [1]



• 树中节点数目在范围 [0, 100]
• -100 <= Node.val <= 100

代码

• 迭代法
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
// 刚开始 循环 有 cur 来保证，后面由 stack 是否为空 来保证（当然访问中间的时候不需要借助 empty()方法 性能有所提高）
while(cur != null || !stack.empty()) {
if(cur != null) {
stack.push(cur);
cur = cur.left;
} else {
cur = stack.pop();
cur = cur.right;
}
}
return res;
}
}

• 递归法
class Solution {
private List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
traversal(root);
return res;
}
private void traversal(TreeNode root) {
if(root == null) {
return;
}
traversal(root.left);
traversal(root.right);
}
}

• 统一迭代法
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root == null) {
return res;
}
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.peek();
if(node != null) {
stack.pop();
if(node.right != null) stack.push(node.right);
stack.push(node);
stack.push(null);
if(node.left != null) stack.push(node.left);
} else {
stack.pop();
node = stack.pop();
}
}
return res;
}
}


3. 145. 二叉树的后序遍历

问题

输入：root = [1,null,2,3]



输入：root = []



输入：root = [1]



• 树中节点的数目在范围 [0, 100]
• -100 <= Node.val <= 100

代码

• 迭代法
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root != null)
stack.push(root);
while(!stack.empty()) {
TreeNode cur = stack.pop();
if(cur.left != null) stack.push(cur.left);
if(cur.right != null) stack.push(cur.right);
}
Collections.reverse(res);
return res;
}
}

• 递归法
class Solution {
private List<Integer> res = new ArrayList<>();
public List<Integer> postorderTraversal(TreeNode root) {
traversal(root);
return res;
}
private void traversal(TreeNode root) {
if(root == null) {
return;
}
traversal(root.left);
traversal(root.right);
}
}

• 统一迭代法
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root == null) {
return res;
}
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.peek();
if(node != null) {
stack.pop();
stack.push(node);
stack.push(null);
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
} else {
stack.pop();
node = stack.pop();
}
}
return res;
}
}


4. 102. 二叉树的层序遍历

问题

输入：root = [3,9,20,null,null,15,7]



输入：root = [1]



输入：root = []



• 树中节点数目在范围 [0, 2000]
• -1000 <= Node.val <= 1000

代码

class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> tempList = new ArrayList<>();
if(root == null) {
return res;
}
queue.offer(root);
while(!queue.isEmpty()) {
int size = queue.size();
while(size-- > 0) {
TreeNode node = queue.poll();
if(node.left != null) queue.offer(node.left);
if(node.right != null) queue.offer(node.right);
}
tempList.clear();
}
return res;
}
}


5. 226. 翻转二叉树

问题

输入：root = [4,2,7,1,3,6,9]



输入：root = [2,1,3]



输入：root = []



代码

invertTree(root->left);         // 左
swap(root->left, root->right);  // 中
invertTree(root->left);         // 注意 这里依然要遍历左孩子，因为中间节点已经翻转了

• 递归法
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) {
return root;
}
invert(root);
return root;
}
private void invert(TreeNode root) {
if(root == null) {
return;
}
// 后序遍历的 思想翻转，由下往上
invert(root.left);
invert(root.right);
TreeNode node = root.left;
root.left = root.right;
root.right = node;
}
}

• 迭代法
// 前序遍历 从上往下 翻转
class Solution {
public TreeNode invertTree(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
if(root == null) {
return root;
}
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.pop();
TreeNode tempNode = node.left;
node.left = node.right;
node.right = tempNode;
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);

}
return root;
}
}


6. 101. 对称二叉树

问题

输入：root = [1,2,2,3,4,4,3]



输入：root = [1,2,2,null,3,null,3]



• 树中节点数目在范围 [1, 1000]
• -100 <= Node.val <= 100

代码

• 递归法
class Solution {
public boolean isSymmetric(TreeNode root) {
return compare(root.left, root.right);

}
private boolean compare(TreeNode left, TreeNode right) {
if(left == null && right != null) {
return false;
} else if(left != null && right == null) {
return false;
} else if(left == null && right == null) {
return true;
} else if(left.val != right.val) {
return false;
}
boolean outside = compare(left.left, right.right);
boolean inside = compare(left.right, right.left);
boolean isSame = outside && inside;
return isSame;
}
}

• 迭代法
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) {
return true;
}
queue.offer(root.left);
queue.offer(root.right);
while(!queue.isEmpty()) {
TreeNode leftNode = queue.poll();
TreeNode rightNode = queue.poll();
// leftNode 和 rightNode 都为空
if(leftNode == null && rightNode == null) {
continue;
}
// leftNode 和 rightNode 有一个 为空，否则两个都不为空时，两者下标的 值不同
if(leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
return false;
}
queue.offer(leftNode.left);
queue.offer(rightNode.right);
queue.offer(leftNode.right);
queue.offer(rightNode.left);
}
return true;
}
}


7. 104. 二叉树的最大深度

代码

• 前序遍历回溯法
class Solution {
private Integer res = 0;
public int maxDepth(TreeNode root) {
if(root == null) return 0;
getDepth(root, 1);
return res;
}
private void getDepth(TreeNode root, Integer depth) {
res = depth > res ? depth : res;
if(root.left != null) {
depth++;
getDepth(root.left, depth);
depth--; // 回溯
}
if(root.right != null) {
depth++;
getDepth(root.right, depth);
depth--; // 回溯
}
return;
}
}


class Solution {
private Integer res = 0;
public int maxDepth(TreeNode root) {
if(root == null) return 0;
getDepth(root, 1);
return res;
}
private void getDepth(TreeNode root, Integer depth) {
res = depth > res ? depth : res;
if(root.left != null)
getDepth(root.left, depth + 1);
if(root.right != null)
getDepth(root.right, depth + 1);
return;
}
}

• 后序遍历递归法
class Solution {
public int maxDepth(TreeNode root) {
return getDepth(root);
}

private int getDepth(TreeNode root) {
if(root == null) {
return 0;
}
int leftDepth = getDepth(root.left);
int rightDepth = getDepth(root.right);
return 1 + Math.max(leftDepth, rightDepth);
}
}


8. 111. 二叉树的最小深度

问题

**说明：**叶子节点是指没有子节点的节点。

输入：root = [3,9,20,null,null,15,7]



输入：root = [2,null,3,null,4,null,5,null,6]



• 树中节点数的范围在 [0, 105]
• -1000 <= Node.val <= 1000

代码

class Solution {
public int minDepth(TreeNode root) {
return getDepth(root);
}
private int getDepth(TreeNode root) {
if(root == null) {
return 0;
}
int leftDepth = getDepth(root.left);
int rightDepth = getDepth(root.right);
if(root.left == null && root.right != null) {
return 1 + rightDepth;
}
if(root.left != null && root.right == null) {
return 1 + leftDepth;
}
return 1 + Math.min(leftDepth, rightDepth);
}
}


9. 222. 完全二叉树的节点个数

问题

输入：root = [1,2,3,4,5,6]



输入：root = []



输入：root = [1]



• 树中节点的数目范围是[0, 5 * 104]
• 0 <= Node.val <= 5 * 104
• 题目数据保证输入的树是 完全二叉树

代码

• 层次遍历迭代法
 // 根据完全二叉树的特性，使用层序遍历解决
class Solution {
public int countNodes(TreeNode root) {
if(root == null) {
return 0;
}
int nodeCount = 0;
queue.offer(root);
while(!queue.isEmpty()) {
nodeCount++;
TreeNode node = queue.poll();
if(node.left != null) queue.offer(node.left);
if(node.right != null) queue.offer(node.right);
}
return nodeCount;
}
}

• 后序遍历递归法
 // 普通二叉树 递归 后序遍历
class Solution {
public int countNodes(TreeNode root) {
return getNoeCounts(root);
}
private int getNoeCounts(TreeNode node) {
if(node == null) {
return 0;
}
int leftNodeCounts = getNoeCounts(node.left);
int rightNodeCounts = getNoeCounts(node.right);
return leftNodeCounts + rightNodeCounts + 1;
}
}


10. 110. 平衡二叉树

问题

输入：root = [3,9,20,null,null,15,7]



输入：root = [1,2,2,3,3,null,null,4,4]



输入：root = []



• 树中的节点数在范围 [0, 5000]
• -104 <= Node.val <= 104

代码

 // 每个节点 的左右两个子树的高度差的绝对值不超过 1
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null) {
return true;
}
return NodeHeigh(root) == -1 ? false : true;
}
// 递归尝试 找到一处 高度差 为 > 1,如有 停止 计算高度，直接 由内到外返回 结果
private int NodeHeigh(TreeNode node) {
if(node == null) {
return 0;
}
int leftHeigh = NodeHeigh(node.left);
int rightHeigh = NodeHeigh(node.right);
if(leftHeigh == -1 || rightHeigh == -1) return -1;
int heigh = Math.max(leftHeigh, rightHeigh) + 1;
return Math.abs(leftHeigh - rightHeigh) > 1 ? -1 : heigh;
}
}


 // 每个节点 的左右两个子树的高度差的绝对值不超过 1
// 前序 遍历 求 深度
class Solution {
public boolean isBalanced(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
if(root == null) {
return true;
}
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.pop();
// 获取 两棵 子树 的高度差
if(Math.abs(getDepth(node.left) - getDepth(node.right)) > 1) {
return false;
}
// 大子树 不超过，遍历 小子树
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
}
return true;
}
// 准确来说 计算的是 节点的高度（该节点到叶子结点）
// 后序 遍历 求 高度
private int getDepth(TreeNode root) {
Integer depth = 0;
Integer res = 0;
Stack<TreeNode> stack = new Stack<>();
if(root == null) {
return 0;
}
stack.push(root);
while(!stack.empty()) {
// 栈存放了 空指针
TreeNode node = stack.peek();
if(node != null) {
node = stack.pop();
stack.push(node);
stack.push(null);
depth++;
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
} else {
// 弹出 空指针
stack.pop();
node = stack.pop();
depth--; // 类似 回溯
}
res = depth > res ? depth : res;
}
return res;
}
}


11. 257. 二叉树的所有路径

输入：root = [1,2,3,null,5]



输入：root = [1]



• 树中节点的数目在范围 [1, 100]
• -100 <= Node.val <= 100

代码

• 递归法
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
if(root == null) {
return res;
}
backtrack(root, res, "");
return res;
}
// 前序递归遍历 所有节点
private void backtrack(TreeNode cur,List<String> res, String path) {
// 不是空节点 加上
path += cur.val;
// 找到 叶子节点
if(cur.left == null && cur.right == null) {
return;
}
if(cur.left != null) backtrack(cur.left, res, path + "->");
// 隐藏了 回溯，path 是 String 类型，不可变类
if(cur.right != null) backtrack(cur.right, res, path + "->");
}
}

• 迭代法
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
if(root == null) {
return res;
}
Stack<String> pathSt = new Stack<>();
Stack<TreeNode> stack = new Stack<>();
pathSt.push(root.val + "");
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.pop();
String path = pathSt.pop();
if(node.left == null && node.right == null) {
}
if(node.right != null) {
pathSt.push(path + "->" + node.right.val);
stack.push(node.right);
}
if(node.left != null) {
pathSt.push(path + "->" + node.left.val);
stack.push(node.left);
}
}
return res;
}
}


12. 100. 相同的树

问题

输入：p = [1,2,3], q = [1,2,3]



输入：p = [1,2], q = [1,null,2]



输入：p = [1,2,1], q = [1,1,2]



• 两棵树上的节点数目都在范围 [0, 100]
• -104 <= Node.val <= 104

代码

• 递归法
 // 前序递归遍历
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null) return true;
else if(p == null && q != null) return false;
else if(p != null && q == null) return false;
else if(p.val != q.val) return false;

boolean leftTreeSame = isSameTree(p.left, q.left);
boolean rightTreeSame = isSameTree(p.right, q.right);
boolean isSame = leftTreeSame && rightTreeSame;
return isSame;
}
}

• 迭代法
 // 层序迭代遍历
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null) return true;
if(p == null || q == null) return false;
// p 和 q 都不等于 null
Stack<TreeNode> stack = new Stack<>();
stack.push(p);
stack.push(q);
while(!stack.empty()) {
TreeNode leftNode = stack.pop();
TreeNode rightNode = stack.pop();
if(leftNode == null && rightNode == null) continue;
if(leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
return false;
}
// leftNode 和 rightNode 都不为 null
stack.push(leftNode.left);
stack.push(rightNode.left);
stack.push(leftNode.right);
stack.push(rightNode.right);
}
return true;
}
}


13. 112. 路径总和

问题

输入：root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22



输入：root = [1,2,3], targetSum = 5

(1 --> 2): 和为 3
(1 --> 3): 和为 4



输入：root = [], targetSum = 0



• 树中节点的数目在范围 [0, 5000]

• 1000 <= Node.val <= 1000

• 1000 <= targetSum <= 1000

代码

• 前序遍历递归法
class Solution {
boolean res = false;
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null) {
return false;
}
backtrack(root, targetSum, root.val);
return res;
}
private void backtrack(TreeNode node, int targetSum, int sum) {
if(node.left == null && node.right == null && sum == targetSum) {
res = true;
}
if(node.left != null) backtrack(node.left, targetSum, sum + node.left.val);
if(node.right != null) backtrack(node.right, targetSum, sum + node.right.val);
}
}

• 前序遍历迭代法
class Solution {
boolean res = false;
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root == null) {
return false;
}
Stack<TreeNode> tNst = new Stack<>();
Stack<Integer> valSt = new Stack<>();
tNst.push(root);
valSt.push(root.val);
while(!tNst.empty()) {
TreeNode node = tNst.pop();
int sum = valSt.pop();
if(node.left == null && node.right == null && sum == targetSum) {
return true;
}
if(node.left != null) {
valSt.push(sum + node.left.val);
tNst.push(node.left);
}
if(node.right != null) {
valSt.push(sum + node.right.val);
tNst.push(node.right);
}
}
return false;
}
}


14. 106. 从中序与后序遍历序列构造二叉树

问题

输入：inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]



输入：inorder = [-1], postorder = [-1]



• 1 <= inorder.length <= 3000
• postorder.length == inorder.length
• -3000 <= inorder[i], postorder[i] <= 3000
• inorderpostorder 都由 不同 的值组成
• postorder 中每一个值都在 inorder
• inorder 保证是树的中序遍历
• postorder 保证是树的后序遍历

代码

• 前序遍历递归法 ( DFS 写法 )
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return backtrack(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
// 左闭右开区间
private TreeNode backtrack(int[] inorder, int inLeft, int inRight, int[] postorder, int postLeft, int postRight) {
int index = inLeft;
if(inLeft == inRight) return null;
TreeNode root = new TreeNode(postorder[postRight - 1]);
// 所以for 循环 终止条件是 < 符合
for(int i = inLeft; i < inRight; i++) {
if(inorder[i] == postorder[postRight - 1]) {
index = i;
break;
}
}
// 找的是 左区间，也就是 左节点
root.left = backtrack(inorder, inLeft, index, postorder, postLeft, postLeft + (index - inLeft));
// 找的是 右区间，也就是 右节点
root.right = backtrack(inorder, index + 1, inRight, postorder, postLeft + (index - inLeft), postRight - 1);
return root;
}
}


15. 105. 从前序与中序遍历序列构造二叉树

问题

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]



输入: preorder = [-1], inorder = [-1]



• 1 <= preorder.length <= 3000
• inorder.length == preorder.length
• -3000 <= preorder[i], inorder[i] <= 3000
• preorderinorder 均 无重复 元素
• inorder 均出现在 preorder
• preorder 保证 为二叉树的前序遍历序列
• inorder 保证 为二叉树的中序遍历序列

代码

• DFS 递归法
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return backtrack(preorder, 0, preorder.length, inorder, 0, inorder.length);
}
private TreeNode backtrack(int[] preorder, int preLeft, int preRight, int[] inorder, int inLeft, int inRight) {
if(inLeft == inRight) return null;
TreeNode root = new TreeNode(preorder[preLeft]);
int index = inLeft;
for(int i = inLeft; i < inRight; i++) {
if(inorder[i] == preorder[preLeft]) {
index = i;
break;
}
}
root.left = backtrack(preorder, preLeft + 1, preLeft + 1 + (index - inLeft), inorder, inLeft, index);
root.right = backtrack(preorder, preLeft + 1 + (index - inLeft), preRight, inorder, index + 1, inRight);
return root;
}
}


16. 654. 最大二叉树

问题

输入：nums = [3,2,1,6,0,5]

- [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 的节点。
- 空数组，无子节点。


输入：nums = [3,2,1]



• 1 <= nums.length <= 1000
• 0 <= nums[i] <= 1000
• nums 中的所有整数 互不相同

代码

class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return recursion(nums, 0, nums.length);
}
private TreeNode recursion(int[] nums, int leftIndex, int rightIndex) {
if(leftIndex == rightIndex) {
return null;
}
int maxIndex = leftIndex;
int max = nums[maxIndex];
for(int i = leftIndex; i < rightIndex; i++) {
if(max < nums[i]) {
max = nums[i];
maxIndex = i;
}
}
TreeNode root = new TreeNode(max);
root.left = recursion(nums, leftIndex, maxIndex);
root.right = recursion(nums, maxIndex + 1, rightIndex);
return root;
}
}


小总结

class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return recursion(nums, 0, nums.length, ...);
}
private TreeNode recursion(int[] nums, int leftIndex, int rightIndex, ...) {
if(leftIndex == rightIndex) {
return null;
}
// 初始化 要创建的节点坐标
int rootIndex = 0;
for(int i = leftIndex; i < rightIndex; i++) {
// 满足创建节点条件
// rootIndex = ?
}
TreeNode root = new TreeNode(nums[rootIndex]);
root.left = recursion(nums, leftIndex, maxIndex, ...);
root.right = recursion(nums, maxIndex + 1, rightIndex, ...);
return root;
}
}


17. 617. 合并二叉树

问题

输入：root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]



输入：root1 = [1], root2 = [1,2]



• 两棵树中的节点数目在范围 [0, 2000]
• -104 <= Node.val <= 104

代码

• 前序遍历递归法
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;
}
}

• 层序遍历迭代法
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1 == null) return root2;
if(root2 == null) return root1;
Stack<TreeNode> stack = new Stack<>();
stack.push(root2);
stack.push(root1);
while(!stack.empty()) {
TreeNode node1 = stack.pop();
TreeNode node2 = stack.pop();
node1.val += node2.val;
if(node1.left != null && node2.left != null) {
stack.push(node2.left);
stack.push(node1.left);
}
if(node1.right != null && node2.right != null) {
stack.push(node2.right);
stack.push(node1.right);
}
// 这里 赋值的 是 node2 的子树（子树！）
if(node1.left == null && node2.left != null) {
node1.left = node2.left;
}
if(node1.right == null && node2.right != null) {
node1.right = node2.right;
}
}
return root1;
}
}


18. 700. 二叉搜索树中的搜索

问题

输入：root = [4,2,7,1,3], val = 2



输入：root = [4,2,7,1,3], val = 5



• 数中节点数在 [1, 5000] 范围内
• 1 <= Node.val <= 107
• root 是二叉搜索树
• 1 <= val <= 107

代码

• 前序遍历递归法
class Solution {
private TreeNode res = null;
public TreeNode searchBST(TreeNode root, int val) {
search(root, val);
return res;
}
private void search(TreeNode root, int val) {
if(root.val == val) {
res = root;
return;
}
if(root.left != null) search(root.left, val);
if(root.right != null) search(root.right, val);
}
}


19. 700. 二叉搜索树中的搜索

问题

输入：root = [4,2,7,1,3], val = 2



输入：root = [4,2,7,1,3], val = 5



• 数中节点数在 [1, 5000] 范围内
• 1 <= Node.val <= 107
• root 是二叉搜索树
• 1 <= val <= 107

代码

class Solution {
public TreeNode searchBST(TreeNode root, int val) {
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.pop();
if(node.val == val) {
return node;
}
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
}
return null;
}
}


20. 98. 验证二叉搜索树

问题

输入：root = [2,1,3]



输入：root = [5,1,4,null,null,3,6]



• 树中节点数目范围在[1, 104]
• -231 <= Node.val <= 231 - 1

代码

• 中序遍历递归法
 // 注意 保存上一个值来比较，初始化要小于 int 类型最小值
class Solution {
private long preVal = ((long)Integer.MIN_VALUE - 1);
private boolean isTrue = true;
public boolean isValidBST(TreeNode root) {
recursion(root);
return isTrue;
}
private void recursion(TreeNode node) {
if(node == null) return;
if(node.left != null && isTrue) recursion(node.left);
if(node.val <= preVal) {
isTrue = false;
return;
}
preVal = node.val;
if(node.right != null & isTrue) recursion(node.right);
}
}

• 中序遍历迭代法
class Solution {
public boolean isValidBST(TreeNode root) {
long preVal = ((long)Integer.MIN_VALUE - 1);
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.peek();
if(node != null) {
stack.pop();
if(node.right != null) stack.push(node.right);
stack.push(node);
stack.push(null);
if(node.left != null) stack.push(node.left);
} else {
stack.pop();
node = stack.pop();
if(node.val <= preVal) {
return false;
}
preVal = node.val;
}
}
return true;
}
}


21. 530. 二叉搜索树的最小绝对差

问题

输入：root = [4,2,6,1,3]



输入：root = [1,0,48,null,null,12,49]



• 树中节点的数目范围是 [2, 104]
• 0 <= Node.val <= 105

代码

• 中序遍历递归法
 // 中序遍历，保存前一元素变量和当前最新差变量
class Solution {
private int diffVal = Integer.MAX_VALUE;
private int preVal = - 100000;
public int getMinimumDifference(TreeNode root) {
recursion(root);
return diffVal;
}
private void recursion(TreeNode node) {
if(node == null) return;
if(node.left != null) recursion(node.left);
int curDiff = node.val - preVal;
if(curDiff < diffVal) {
diffVal = curDiff;
}
preVal = node.val;
if(node.right != null) recursion(node.right);
}
}

• 中序遍历迭代法
 // 中序遍历，保存前一元素变量和当前最新差变量
class Solution {
public int getMinimumDifference(TreeNode root) {
int diffVal = Integer.MAX_VALUE;
int preVal = - 100000;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.peek();
if(node != null) {
stack.pop();
if(node.right != null) stack.push(node.right);
stack.push(node);
stack.push(null);
if(node.left != null) stack.push(node.left);
} else {
stack.pop();
node = stack.pop();
int curDiff = node.val - preVal;
if(curDiff < diffVal) {
diffVal = curDiff;
}
preVal = node.val;
}
}
return diffVal;
}
}


22. 501. 二叉搜索树中的众数

问题

输入：root = [1,null,2,2]



输入：root = [0]



• 树中节点的数目在范围 [1, 104]
• -105 <= Node.val <= 105

代码

• 中序遍历迭代法
class Solution {
public int[] findMode(TreeNode root) {
int preVal = - 100000 - 1;
List<Integer> res = new ArrayList<>();
int maxTime = 1;
int currentTime = 1;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.peek();
if(node != null) {
stack.pop();
if(node.right != null) stack.push(node.right);
stack.push(node);
stack.push(null);
if(node.left != null) stack.push(node.left);
} else {
stack.pop();
node = stack.pop();
// 先 判断 是否有 相同元素 来 计当前元素 次数
if(node.val == preVal) {
currentTime++;
} else {
currentTime = 1;
}
// 再 通过 相同元素次数 和最大次数 比较
// 相等就 再加入结果
if(currentTime == maxTime) {
// 存在 一个元素 比之前 次数还多的，那之前的就不要了,把当前的元素 加入结果
} else if(currentTime > maxTime) {
maxTime = currentTime;
res.clear();
}
preVal = node.val;
}
}
return Arrays.stream(res.toArray(new Integer[0])).mapToInt(Integer::intValue).toArray();
}
}

• 中序遍历递归法
class Solution {
private int preVal = - 100000 - 1;
private List<Integer> res = new ArrayList<>();
private int maxTime = 1;
private int currentTime = 1;
public int[] findMode(TreeNode root) {
recursion(root);
int[] intRes = new int[res.size()];
for(int i = 0; i < res.size(); i++) {
intRes[i] = res.get(i);
}
return intRes;
}
private void recursion(TreeNode node) {
if(node.left != null )recursion(node.left);
if(node.val == preVal) {
currentTime++;
} else {
currentTime = 1;
}
// 再 通过 相同元素次数 和最大次数 比较
// 相等就 再加入结果
if(currentTime == maxTime) {
// 存在 一个元素 比之前 次数还多的，那之前的就不要了,把当前的元素 加入结果
} else if(currentTime > maxTime) {
maxTime = currentTime;
res.clear();
}
preVal = node.val;
if(node.right != null) recursion(node.right);
}
}


23. 236. 二叉树的最近公共祖先

问题

输入：root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1



输入：root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4



输入：root = [1,2], p = 1, q = 2



-109 <= Node.val <= 109

p != q
p 和 q 均存在于给定的二叉树中。

代码

• 后序遍历递归法
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 终止条件，找不到 返回 null，否则 返回 目标节点
if(root == null || root == p || root == q) return root;
// 后序递归
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
// 由 公共 祖先 找到，而且 公共祖先 不为 left 或 right
if(left != null && right != null) {
return root;
}
// 由 left 子树中 找到，右侧中 没有 p 和 q，而且 找到的 必然是 节点更高的 那个(后序遍历)
if(left != null && right == null) {
return left;
// 由 right 子树中 找到，左侧中 没有 p 和 q，而且 找到的 必然是 节点更高的 那个(后序遍历)
} else if(left == null && right != null) {
return right;
} else {
return null;
}
}
}


24. 235. 二叉搜索树的最近公共祖先

问题

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8



输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4



• 所有节点的值都是唯一的。
• p、q 为不同节点且均存在于给定的二叉搜索树中。

代码

• 迭代法
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(root != null) {
if(root.val < p.val && root.val < q.val) {
root = root.right;
} else if(root.val > p.val && root.val > q.val) {
root = root.left;
} else {
break;
}
}
return root;
}
}

• 递归法
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root.val < Math.min(p.val, q.val)) {
return lowestCommonAncestor(root.right, p, q);
} else if (root.val > Math.max(p.val, q.val)) {
return lowestCommonAncestor(root.left, p, q);
}
return root;
}
}


25. 701. 二叉搜索树中的插入操作

问题

输入：root = [4,2,7,1,3], val = 5



输入：root = [40,20,60,10,30,50,70], val = 25



输入：root = [4,2,7,1,3,null,null,null,null,null,null], val = 5



• 树中的节点数将在 [0, 104]的范围内。
• -108 <= Node.val <= 108
• 所有值 Node.val独一无二 的。
• -108 <= val <= 108
• 保证 val 在原始BST中不存在。

代码

• 递归法（找到 对应 位置，回溯后 指向解决）
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
// 向下搜索到 指定 空节点位置，回溯后由对应的 父节点的对应 子节点 指向待插入节点就可以了
if(root == null) {
return new TreeNode(val);
}
if(root.val > val) root.left = insertIntoBST(root.left, val);
if(root.val < val) root.right = insertIntoBST(root.right, val);
return root;
}
}

• 迭代法
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null) {
return new TreeNode(val);
}
TreeNode pre = root;
TreeNode cur = root;
while(cur != null) {
pre = cur;
if(cur.val < val) {
cur = cur.right;
} else {
cur = cur.left;
}
}
if(pre.val < val) {
pre.right = new TreeNode(val);
} else {
pre.left = new TreeNode(val);
}
return root;
}
}


26. 450. 删除二叉搜索树中的节点

问题

输入：root = [5,3,6,2,4,null,7], key = 3



输入: root = [5,3,6,2,4,null,7], key = 0



输入: root = [], key = 0



• 节点数的范围 [0, 104].
• -105 <= Node.val <= 105
• 节点值唯一
• root 是合法的二叉搜索树
• -105 <= key <= 105

代码

• 递归法
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) return null;
if(root.val == key) {
if(root.left == null && root.right == null) {
return null;
} else if(root.left == null) {
TreeNode target = root.right;
// gc 垃圾 回收
root.right = null;
return target;
} else if(root.right == null) {
TreeNode target = root.left;
// gc 垃圾 回收
root.left = null;
return target;
} else {
TreeNode cur = root.right;
TreeNode target = cur;
while(cur.left != null) {
cur = cur.left;
}
cur.left = root.left;
// gc 回收
root.left = null;
root.right = null;
return target;
}
}
if(root.val > key) root.left = deleteNode(root.left, key);
if(root.val < key) root.right = deleteNode(root.right, key);
return root;
}
}


小总结

class Solution {
public TreeNode recursion(TreeNode root, int key) {
// 查找到 具体位置，但为空
if(root == null) {
/*具体操作*/
return /**/;
}
// 找到 具体 元素位置
if(root.val == key) {

}
root.left = recursion(root.left, key);
root.right = recursion(root.right, key);
return root;
}
}


669. 修剪二叉搜索树

问题

输入：root = [1,0,2], low = 1, high = 2



输入：root = [3,0,4,null,2,null,null,1], low = 1, high = 3



0 <= Node.val <= 104

0 <= low <= high <= 104

代码

• 递归法

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);
}
if(root.val > high) {
return trimBST(root.left, low, high);
}
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
}

• 迭代法
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null) {
return null;
}
// 遍历二叉搜索树找到第一个节点 处在 区间low - high
// 这一步也是在做 修减
while(root != null && (root.val < low || root.val > high)) {
if(root.val < low) root = root.right;
if(root.val > high) root = root.left;
}
TreeNode cur = root;
// 这样，左边的节点值不可能大于 high，只要修减 小于 low
while(cur != null) {
while(cur.left != null && cur.left.val < low) {
// 左子树root 节点值小，删除 左子树中的 左子树
cur.left = cur.left.right;
}
// 遍历比 被修减的节点值更大的 节点
cur = cur.left;
}
cur = root;
// 右边的 节点值 不可能 小于 low，只要修减 大于 high
while(cur != null) {
while(cur.right != null && cur.right.val > high) {
// 右子树root 节点值大，删除 右子树中的 右子树
cur.right = cur.right.left;
}
// 遍历比 被修减的节点值更小的 节点
cur = cur.right;
}
return root;
}
}


108. 将有序数组转换为二叉搜索树

问题

输入：nums = [-10,-3,0,5,9]



输入：nums = [1,3]



• 1 <= nums.length <= 104
• -104 <= nums[i] <= 104
• nums严格递增 顺序排列

代码

• 递归法
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return recursion(nums, 0, nums.length);
}
// 定义 为左闭右开的区间
private TreeNode recursion(int[] nums, int left, int right) {
// 已经取不到值了
if(left == right) {
return null;
}
int rootIndex = left + (right - left) / 2;
TreeNode root = new TreeNode(nums[rootIndex]);
root.left = recursion(nums, left, rootIndex);
root.right = recursion(nums, rootIndex + 1, right);
return root;
}
}

• 迭代法
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
if(nums.length == 0) {
return null;
}
TreeNode root = new TreeNode(0);
nodeQueue.offer(root);
leftQueue.offer(0);
rightQueue.offer(nums.length);
while(!nodeQueue.isEmpty()) {
TreeNode curNode = nodeQueue.poll();
int left = leftQueue.poll();
int right = rightQueue.poll();
int mid = left + (right - left) / 2;
// 处理每个元素
curNode.val = nums[mid];
// 左闭右开 区间 任由元素
if(left < mid) {
curNode.left = new TreeNode(0);
nodeQueue.offer(curNode.left);
leftQueue.offer(left);
rightQueue.offer(mid);
}
// 左闭右开 区间 仍有元素
if(right > mid + 1) {
curNode.right = new TreeNode(0);
nodeQueue.offer(curNode.right);
leftQueue.offer(mid + 1);
rightQueue.offer(right);
}
}
return root;
}
}


538. 把二叉搜索树转换为累加树

问题

• 节点的左子树仅包含键 小于 节点键的节点。
• 节点的右子树仅包含键 大于 节点键的节点。
• 左右子树也必须是二叉搜索树。

输入：[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]



输入：root = [0,null,1]



输入：root = [1,0,2]



输入：root = [3,2,4,1]



• 树中的节点数介于 0104 之间。
• 每个节点的值介于 -104104 之间。
• 树中的所有值 互不相同
• 给定的树为二叉搜索树。

代码

• 递归法

class Solution {
private int sumWeight = 0;
public TreeNode convertBST(TreeNode root) {
if(root == null) {
return null;
}
recursion(root);
return root;
}
private void recursion(TreeNode node) {
if(node.right != null) recursion(node.right);
sumWeight += node.val;
node.val = sumWeight;
if(node.left != null) recursion(node.left);
}
}

• 迭代法
class Solution {
private int sumWeight = 0;
public TreeNode convertBST(TreeNode root) {
if(root == null) {
return null;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.peek();
if(node != null) {
stack.pop();
if(node.left != null) stack.push(node.left);
stack.push(node);
stack.push(null);
if(node.right != null) stack.push(node.right);
} else {
stack.pop();
node = stack.pop();
sumWeight += node.val;
node.val = sumWeight;
}
}
return root;
}
}


二叉树总结

• 普通二叉树：普通遍历方式
• 完全二叉树：层次遍历 + 队列
• 二叉搜索树：中序遍历 + 递归，中序遍历 + 迭代，添加节点，修改节点
• 二叉平衡搜索树：有序数组 + 递归 构造平衡搜索树
• 最大树：第 n 个 最大值
• 最小树：第 n 个 最小值

二、结束语

—— 嗝屁小孩纸 QQ：1160886967

—— 其他平台：CSDN51CTO博客园

—— 转发于个人博客对应 二叉树 题型

—— GitHub 专栏：Fyupeng

• 0
点赞
• 0
收藏
• 打赏
• 0
评论
05-14 239
11-13 740
08-23 1971
09-15 212
07-15 207
03-05 509
04-24 678

“相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。