1.二叉树的遍历方式
2-144.二叉树的递归遍历🟢
题目:给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
代码:
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
traversal(root, res);
return res;
}
public void traversal(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
res.add(root.val); // 中(放到中间就是中序遍历,放到最下边就是后序遍历)
traversal(root.left, res); // 左
traversal(root.right, res); // 右
}
}
3-144.二叉树的迭代遍历🟢
题目:给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
代码:
class Solution {
// 前序遍历顺序:中-左-右,入栈顺序:中-右-左
// 首先将根入栈,因为栈是FILO,所以要先将右结点入栈,再将左结点入栈
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
Deque<TreeNode> stack = new LinkedList<>();
if (root == null) return res;
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop(); // 中
res.add(node.val);
if (node.right != null) {
stack.push(node.right); // 右
}
if (node.left != null) {
stack.push(node.left); // 左
}
}
return res;
}
}
后序迭代方式遍历代码:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
// 前序遍历返回的res是根左右,如果调换while中右左入栈的顺序
// 就会得到根右左顺序的res,将res反转就会得到左右根
List<Integer> res = new LinkedList<>();
if (root == null) return res;
Deque<TreeNode> stack = new LinkedList<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop(); // 中
res.add(node.val);
if (node.left != null) {
stack.push(node.left); // 左
}
if (node.right != null) {
stack.push(node.right); // 右
}
}
Collections.reverse(res); // 反转
return res;
}
}
中序迭代方式遍历代码:
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
// 首先判断当前结点是否为空,不为空将当前结点的左结点入栈,
// 若为空,取栈顶元素加入res,将栈顶元素的右结点作为当前结点
// 继续重复上面步骤,直到当前结点为空且栈为空为止。
List<Integer> res = new LinkedList<>();
if (root == null) return res;
Deque<TreeNode> stack = new LinkedList<>();
TreeNode node = root;
while (node != null || !stack.isEmpty()) {
if (node != null) {
stack.push(node);
node = node.left;
} else {
node = stack.pop();
res.add(node.val);
node = node.right;
}
}
return res;
}
}
5-102.二叉树的层序遍历🟡
题目:给你二叉树的根节点 root
,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
链接:二叉树的层序遍历
代码:
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while (!q.isEmpty()) {
int len = q.size();
// 记录这一层的节点值
List<Integer> level = new LinkedList<>();
// for 循环控制每一层从左向右遍历
for (int i = 0; i < len; i++) {
TreeNode cur = q.poll();
level.add(cur.val);
if (cur.left != null)
q.offer(cur.left);
if (cur.right != null)
q.offer(cur.right);
}
res.add(level);
}
return res;
}
}
2.求二叉树的属性
8-101.对称二叉树🟢
题目:给你一个二叉树的根节点 root
,检查它是否轴对称。
链接:101. 对称二叉树
代码:
class Solution {
public boolean isSymmetric(TreeNode root) {
// 对称二叉树,对称的是根的左右子树
// 不能完全遍历左右子树之后比较遍历结果,因为不能区分左结点或右结点为空的情况
// 左子树通过根左右的方式遍历
// 右子树通过根右左的方式遍历
// 若左右子树遍历的结果相同,则是对称二叉树
TreeNode left = root.left;
TreeNode right = root.right;
return inorder(left, right);
}
public boolean inorder(TreeNode left, TreeNode right) {
if (left == null && right != null) return false;
if (left != null && right == null) return false;
if (left == null && right == null) return true;
if (left.val != right.val) return false;
//前序遍历
boolean f1 = inorder(left.left, right.right);
boolean f2 = inorder(left.right, right.left);
return f1 && f2;
}
}
9-104.二叉树的最大深度🟢
题目:给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
代码:
class Solution {
public int maxDepth(TreeNode root) {
// 求二叉树的深度本质上是遍历二叉树
// 这里使用后序遍历求二叉树的深度
if (root == null) return 0;
int leftDepth = maxDepth(root.left);
int rightDepth = maxDepth(root.right);
return 1 + Math.max(leftDepth, rightDepth);
}
}
10-111.二叉树的最小深度🟢
题目:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
代码:
class Solution {
/**
* 递归法,相比求MaxDepth要复杂点
* 因为最小深度是从根节点到最近叶子节点的最短路径上的节点数量
*/
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if (root.left == null) {
return rightDepth + 1;
}
if (root.right == null) {
return leftDepth + 1;
}
// 左右结点都不为null
return Math.min(leftDepth, rightDepth) + 1;
}
}
11-222.完全二叉树的节点个数🟢
题目:给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1~ 2h
个节点。
代码:
1.通用解法
class Solution {
// 通用递归解法
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
return countNodes(root.left) + countNodes(root.right) + 1;
}
}
2.针对完全二叉树的解法
class Solution {
// 满二叉树的结点数为:2^depth - 1
public int countNodes(TreeNode root) {
if (root == null) return 0;
TreeNode left = root.left;
TreeNode right = root.right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
while (left != null) { // 求左子树深度
left = left.left;
leftDepth++;
}
while (right != null) { // 求右子树深度
right = right.right;
rightDepth++;
}
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
}
return countNodes(root.left) + countNodes(root.right) + 1;
}
}
12-110.平衡二叉树🟢
题目:给定一个二叉树,判断它是否是高度平衡的二叉树
链接:110. 平衡二叉树
代码:
class Solution {
public boolean isBalanced(TreeNode root) {
return height(root) >= 0;
}
// 定义:给一个根节点,返回它的高度,负数代表该树不平衡
public int height(TreeNode root) {
if (root == null) {
return 0;
}
int leftHeight = height(root.left);
int rightHeight = height(root.right);
// 如果高度差大于1返回-1表示当前子树不平衡
// 上一级的父节点获取到子节点返回的-1后也返回-1,表示父节点同样也是不平衡的
if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {
return -1;
} else {
return Math.max(leftHeight, rightHeight) + 1;
}
}
}
13-257.二叉树的所有路径🟢
题目:给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
链接:二叉树的所有路径
代码:
class Solution {
List<String> res = new ArrayList<>();
public List<String> binaryTreePaths(TreeNode root) {
if(root == null) return new ArrayList<>();
// 参数:根节点 当前遍历路径
traversal(root, "");
return res;
}
public void traversal(TreeNode root, String path) {
// 递归结束条件是遇到叶子节点,则将当前路径添加到结果中
if(root.left == null && root.right == null){
res.add(new StringBuilder(path).append(root.val).toString());
return;
}
String tmp = new StringBuilder(path).append(root.val).append("->").toString();
if(root.left != null) traversal(root.left,tmp);
if(root.right != null) traversal(root.right,tmp);
}
}
15-404.左叶子之和🟢
题目:给定二叉树的根节点 root
,返回所有左叶子之和。
链接:左叶子之和
代码:
class Solution {
int res =0;
public int sumOfLeftLeaves(TreeNode root) {
traversal(root);
return res;
}
public void traversal(TreeNode root){
if(root == null){
return;
}
// 前序遍历,判断当前根节点的左子节点是不是左叶子
if(root.left!=null&&root.left.left==null&&root.left.right==null){
res += root.left.val;
}
traversal(root.left);
traversal(root.right);
}
}
16-513.找树左下角的值🟡
题目:给定一个二叉树的 根节点 root
,请找出该二叉树的 最底层 最左边 节点的值。假设二叉树中至少有一个节点。
链接:找树左下角的值
代码:
1.递归解法(不推荐)
class Solution {
int maxDeep = -1;
int res = 0;
public int findBottomLeftValue(TreeNode root) {
traversal(root,0);
return res;
}
public void traversal (TreeNode root,int deep) {
if (root == null)
return;
// 遇到叶子节点开始判断
if (root.left == null && root.right == null) {
// 先左后右,所以可以直接判断当前高度是否大于最大高度
if (deep > maxDeep) {
res = root.val;
maxDeep = deep;
}
}
traversal(root.left,deep + 1);
traversal(root.right,deep + 1);
}
}
2.迭代解法(推荐)
class Solution {
public int findBottomLeftValue(TreeNode root) {
int res = root.val;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while (!q.isEmpty()) {
int len = q.size();
// for 循环控制每一层从左向右遍历
for (int i = 0; i < len; i++) {
TreeNode cur = q.poll();
// 这一层的第一个节点也就是最左边的
if(i == 0){
res = cur.val;
}
if (cur.left != null)
q.offer(cur.left);
if (cur.right != null)
q.offer(cur.right);
}
}
return res;
}
}
17-112.路径总和🟢
题目:给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。
链接:路径总和
代码:
1.我的解法(易理解但不推荐)
class Solution {
boolean res = false;
public boolean hasPathSum(TreeNode root, int targetSum) {
traversal(root,0,targetSum);
return res;
}
// 对树做前序遍历,但若找到则不再进行后续遍历
public void traversal(TreeNode root,int sum,int targetSum){
// 节点为空或已经找到了路径就直接返回
// 我是手动判断下!res时不再递归,但可以给函数设置返回值停止后续递归
if(root == null || res){
return;
}
// 是叶子节点且累加值等于目标值
if(root.left == null && root.right == null && root.val+sum == targetSum){
res = true;
}
int tmp = root.val+sum;
traversal(root.left,tmp,targetSum);
traversal(root.right,tmp,targetSum);
}
}
2.官方解法(推荐)
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
// 碰到叶子节点判断当前剩余值是否等于叶子节点值
if (root.left == null && root.right == null) {
return sum == root.val;
}
// 在递归函数里操作sum,相当于返回的时候会回溯到之前的状态
// 如果左子树或右子树中找到了路径就直接返回true,程序就不再继续遍历剩下路径了
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
}
扩展:113.路径总和
题目:给你二叉树的根节点 root
和一个整数目标和 targetSum
,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
链接:路径总和 II
代码:
class Solution {
List<List<Integer>> res = new LinkedList<List<Integer>>();
Deque<Integer> path = new LinkedList<Integer>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
traversal(root, targetSum);
return res;
}
public void traversal(TreeNode root, int targetSum) {
if (root == null) {
return;
}
path.offerLast(root.val);
targetSum -= root.val;
if (root.left == null && root.right == null && targetSum == 0) {
res.add(new LinkedList<Integer>(path));
}
traversal(root.left, targetSum);
traversal(root.right, targetSum);
// 弹出一个元素相当于回溯到之前的状态
path.pollLast();
}
}
3.二叉树的修改与构造
6-226.翻转二叉树🟢
题目:给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
链接:226. 翻转二叉树
代码:
class Solution {
public TreeNode invertTree(TreeNode root) {
// 翻转二叉树,实际上就是交换左右结点
// 使用递归来交换,根左右
if(root == null) return null;
swapChildren(root);
invertTree(root.left);
invertTree(root.right);
return root;
}
public void swapChildren(TreeNode root){
TreeNode temp = root.right;
root.right = root.left;
root.left = temp;
}
}
18-106.从中序与后序遍历序列构造二叉树🟡
题目:给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
代码:
class Solution {
// 存储 inorder 中值到索引的映射
HashMap<Integer, Integer> valToIndex = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
for (int i = 0; i < inorder.length; i++) {
valToIndex.put(inorder[i], i);
}
return build(inorder, 0, inorder.length - 1,
postorder, 0, postorder.length - 1);
}
/*
定义:
中序遍历数组为 inorder[inStart..inEnd],
后序遍历数组为 postorder[postStart..postEnd],
构造这个二叉树并返回该二叉树的根节点
*/
public TreeNode build(int[] inorder, int inStart, int inEnd,
int[] postorder, int postStart, int postEnd) {
if (inStart > inEnd) {
return null;
}
// root 节点对应的值就是后序遍历数组的最后一个元素
int rootVal = postorder[postEnd];
// rootVal 在中序遍历数组中的索引
int index = valToIndex.get(rootVal);
// 左子树的节点个数
int leftSize = index - inStart;
TreeNode root = new TreeNode(rootVal);
// 递归构造左右子树
root.left = build(inorder, inStart, index - 1,
postorder, postStart, postStart + leftSize - 1);
root.right = build(inorder, index + 1, inEnd,
postorder, postStart + leftSize, postEnd - 1);
return root;
}
}
19-654.最大二叉树🟡
题目:给定一个不重复的整数数组 nums
。 最大二叉树 可以用下面的算法从 nums
递归地构建:
- 创建一个根节点,其值为
nums
中的最大值。 - 递归地在最大值 左边 的 子数组前缀上 构建左子树。
- 递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums
构建的 最大二叉树 。
链接:最大二叉树
代码:
class Solution {
/* 主函数 */
public TreeNode constructMaximumBinaryTree(int[] nums) {
return build(nums, 0, nums.length - 1);
}
/* 定义:将 nums[lo..hi] 构造成符合条件的树,返回根节点 */
public TreeNode build(int[] nums, int lo, int hi) {
if (lo > hi) {
return null;
}
// 找到数组中的最大值和对应的索引
int index = -1, maxVal = Integer.MIN_VALUE;
for (int i = lo; i <= hi; i++) {
if (maxVal < nums[i]) {
index = i;
maxVal = nums[i];
}
}
TreeNode root = new TreeNode(maxVal);
// 递归调用构造左右子树
root.left = build(nums, lo, index - 1);
root.right = build(nums, index + 1, hi);
return root;
}
}
21-617.合并二叉树🟢
题目:给你两棵二叉树: root1
和 root2
。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。注意: 合并过程必须从两个树的根节点开始。
链接:617. 合并二叉树
代码:
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;
}
}
4.二叉树公共祖先问题
26-236.二叉树的最近公共祖先🟡
题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
代码:
class Solution {
// 定义:输入三个参数 root,p,q,根据左右子树遍历结果返回一个节点
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);
// 情况 1
if (left != null && right != null) {
return root;
}
// 情况 2
if (left == null && right == null) {
return null;
}
// 情况 3
return left == null ? right : left;
}
}
28-235.二叉搜索树的最近公共祖先🟡
题目:给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
代码:
1.递归解法
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;
}
}
2.迭代解法
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while (true) {
// 如果当前节点比两个待查节点大,就往左子树找
if (root.val > p.val && root.val > q.val) {
root = root.left;
// 如果当前节点比两个待查节点小,就往右子树找
} else if (root.val < p.val && root.val < q.val) {
root = root.right;
// 找到最终节点,跳出循环
} else {
break;
}
}
return root;
}
}
5.求二叉搜索树的属性
22-700.二叉搜索树中的搜索🟢
题目:给定二叉搜索树(BST)的根节点 root
和一个整数值 val
。
你需要在 BST 中找到节点值等于 val
的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null
。
代码:
1.递归解法
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
if (root == null || root.val == val) {
return root;
}
// 目标值小于当前值则去左子树搜索
if (val < root.val) {
return searchBST(root.left, val);
}
// 目标值大于当前值则去右子树搜索
if (val > root.val) {
return searchBST(root.right, val);
}
return root;
}
}
2.迭代解法
class Solution {
// 利用二叉搜索树特点,优化,可以不需要栈
public TreeNode searchBST(TreeNode root, int val) {
while (root != null)
if (val < root.val) {
root = root.left;
} else if (val > root.val) {
root = root.right;
} else return root;
return null;
}
}
23-98.验证二叉搜索树🟡
题目:给你一个二叉树的根节点 root
,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
链接:98. 验证二叉搜索树
代码:
class Solution {
// 记录前一个节点的值
public long prev = Long.MIN_VALUE;
// 二叉搜索树中序遍历得到的是一个递增的序列,也可以用一个数组记录再判断数组是否递增
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
if (!isValidBST(root.left)) {
return false;
}
// 当前节点小于等于前一个节点的值则不满足二叉搜索树条件
if (root.val <= prev) {
return false;
}
prev = root.val;
return isValidBST(root.right);
}
}
24-530.二叉搜索树的最小绝对差🟢
题目:给你一个二叉搜索树的根节点 root
,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
代码:
class Solution {
TreeNode prev = null;
int res = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
traverse(root);
return res;
}
void traverse(TreeNode root) {
if (root == null) {
return;
}
traverse(root.left);
// 中序遍历位置
if (prev != null) {
// 记录最小值
res = Math.min(res, root.val - prev.val);
}
prev = root;
traverse(root.right);
}
}
25-501.二叉搜索树中的众数🟢
题目:给你一个含重复值的二叉搜索树(BST)的根节点 root
,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
假定 BST 满足如下定义:
- 结点左子树中所含节点的值 小于等于 当前节点的值
- 结点右子树中所含节点的值 大于等于 当前节点的值
- 左子树和右子树都是二叉搜索树
代码:
class Solution {
ArrayList<Integer> resList = new ArrayList<>();
public int maxCount = 0;
public int count = 0;
public TreeNode pre = null;
public int[] findMode(TreeNode root) {
traversal(root);
// 将resList的元素拷贝到res数组中
int[] res = new int[resList.size()];
for (int i = 0; i < resList.size(); i++) {
res[i] = resList.get(i);
}
return res;
}
public void traversal(TreeNode root) {
if (root == null) {
return;
}
traversal(root.left);
// 计数
if (pre == null || root.val != pre.val) {
count = 1;
} else {
count++;
}
// 更新结果以及maxCount
if (count > maxCount) {
resList.clear();
resList.add(root.val);
maxCount = count;
} else if (count == maxCount) {
resList.add(root.val);
}
// 记录前一个节点
pre = root;
traversal(root.right);
}
}
6.二叉搜索树的修改与构造
29-701.二叉搜索树中的插入操作🟡
题目:给定二叉搜索树(BST)的根节点 root
和要插入树中的值 value
,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
代码:
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
// 找到空位置返回待插入节点
if (root == null) {
return new TreeNode(val);
}
if (root.val < val) {
// 插入节点操作,insertIntoBST函数返回值就是待插入节点
root.right = insertIntoBST(root.right, val);
}
if (root.val > val) {
root.left = insertIntoBST(root.left, val);
}
// 返回根节点给上一层
return root;
}
}
30-450.删除二叉搜索树中的节点🟡
题目:给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
代码:
1.代码随想录解法:左子树添加到右子树最左边,返回删除节点右孩子为新的当前根节点
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
//分为五种情况:
// 1.未找到,直接返回root
if (root == null) return root;
if (root.val == key) {
// 2.找到的节点左子树为空,右子树非空,右子树补上
if (root.left == null && root.right != null) {
return root.right;
// 3.找到的节点右子树为空,左子树非空,左子树补上
} else if (root.left != null && root.right == null) {
return root.left;
// 4.找到的节点左右子树都为空,直接删除
} else if (root.left == null && root.right == null) {
return null;
// 5.找到的节点左右子树都非空,左子树添加到右子树最左边,
// 返回删除节点右孩子为新的根节点
} else {
TreeNode node = root.right;
while (node.left != null) {
node = node.left;
}
node.left = root.left;
return root.right;
}
}
if (root.val > key) root.left = deleteNode(root.left, key);
if (root.val < key) root.right = deleteNode(root.right, key);
return root;
}
}
2.labuladong 解法:右子树最小节点替换待删节点,再把待删节点删了
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null;
if (root.val == key) {
// 这两个 if 把情况 1 和 2 都正确处理了
if (root.left == null) return root.right;
if (root.right == null) return root.left;
// 处理情况 3
// 获得右子树最小的节点
TreeNode minNode = getMin(root.right);
// 删除右子树最小的节点
root.right = deleteNode(root.right, minNode.val);
// 用右子树最小的节点替换 root 节点
minNode.left = root.left;
minNode.right = root.right;
root = minNode;
} else if (root.val > key) {
root.left = deleteNode(root.left, key);
} else if (root.val < key) {
root.right = deleteNode(root.right, key);
}
return root;
}
TreeNode getMin(TreeNode node) {
// BST 最左边的就是最小的
while (node.left != null) node = node.left;
return node;
}
}
31-669.修剪二叉搜索树🟡
题目:给你二叉搜索树的根节点 root
,同时给定最小边界low
和最大边界 high
。通过修剪二叉搜索树,使得所有节点的值在[low, high]
中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
链接:669. 修剪二叉搜索树
代码:
class Solution {
// 函数定义:满足区间返回root,不满足则返回root的符合条件的子节点
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) {
return null;
}
if (root.val < low) {
// 当前节点比low小那就去右边寻找符合区间[low, high]的节点
return trimBST(root.right, low, high);
}
if (root.val > high) {
return trimBST(root.left, low, high);
}
// root.left接入符合条件的左孩子
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
}
32-108.将有序数组转换为二叉搜索树🟡
题目:给你一个整数数组 nums
,其中元素已经按 升序 排列,请你将其转换为一棵平衡二叉搜索树。
代码:
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
TreeNode root = traversal(nums, 0, nums.length - 1);
return root;
}
// 左闭右闭区间[left, right]
// 函数定义:根据数组和给定区间构造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;
}
}
33-538.把二叉搜索树转换为累加树🟡
题目:给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node
的新值等于原树中大于或等于 node.val
的值之和。
代码:
class Solution {
public TreeNode convertBST(TreeNode root) {
traverse(root);
return root;
}
int sum = 0;
// 右中左遍历,累加节点的值
void traverse(TreeNode root) {
if (root == null) {
return;
}
traverse(root.right);
// 维护累加和
sum += root.val;
// 将 BST 转化成累加树
root.val = sum;
traverse(root.left);
}
}