文章目录
- 1.二叉树的遍历方式
- 2-144.二叉树的递归遍历🟢
- 3-144.二叉树的迭代遍历🟢
- 5-102.二叉树的层序遍历🟡
- 2.求二叉树的属性
- 8-101.对称二叉树🟢
- 9-104.二叉树的最大深度🟢
- 10-111.二叉树的最小深度🟢
- 11-222.完全二叉树的节点个数🟢
- 12-110.平衡二叉树🟢
- 13-257.二叉树的所有路径🟢
- 15-404.左叶子之和🟢
- 16-513.找树左下角的值🟡
- 17-112.路径总和🟢
- 3.二叉树的修改与构造
- 6-226.翻转二叉树🟢
- 18-106.从中序与后序遍历序列构造二叉树🟡
- 19-654.最大二叉树🟡
- 21-617.合并二叉树🟢
- 4.二叉树公共祖先问题
- 26-236.二叉树的最近公共祖先🟡
- 28-235.二叉搜索树的最近公共祖先🟡
- 5.求二叉搜索树的属性
- 22-700.二叉搜索树中的搜索🟢
- 23-98.验证二叉搜索树🟡
- 24-530.二叉搜索树的最小绝对差🟢
- 25-501.二叉搜索树中的众数🟢
- 6.二叉搜索树的修改与构造
- 29-701.二叉搜索树中的插入操作🟡
- 30-450.删除二叉搜索树中的节点🟡
- 31-669.修剪二叉搜索树🟡
- 32-108.将有序数组转换为二叉搜索树🟡
- 33-538.把二叉搜索树转换为累加树🟡
1.二叉树的遍历方式
2-144.二叉树的递归遍历🟢
题目:给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
链接:144. 二叉树的前序遍历
代码:
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
,返回它节点值的 前序 遍历。
链接:144. 二叉树的前序遍历
代码:
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
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
链接:104. 二叉树的最大深度
代码:
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.二叉树的最小深度🟢
题目:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
链接: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;}// 左右结点都不为nullreturn Math.min(leftDepth, rightDepth) + 1;}
}
11-222.完全二叉树的节点个数🟢
题目:给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1~ 2h
个节点。
链接:222. 完全二叉树的节点个数
代码:
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 - 1public 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.二叉树的最近公共祖先🟡
题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
链接: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);// 情况 1if (left != null && right != null) {return root;}// 情况 2if (left == null && right == null) {return null;}// 情况 3return left == null ? right : left;}
}
28-235.二叉搜索树的最近公共祖先🟡
题目:给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
链接: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
。
链接:700. 二叉搜索树中的搜索
代码:
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
,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
链接:530. 二叉搜索树的最小绝对差
代码:
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 满足如下定义:
- 结点左子树中所含节点的值 小于等于 当前节点的值
- 结点右子树中所含节点的值 大于等于 当前节点的值
- 左子树和右子树都是二叉搜索树
链接:501. 二叉搜索树中的众数
代码:
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
,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
链接:701. 二叉搜索树中的插入操作
代码:
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 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
链接:450. 删除二叉搜索树中的节点
代码:
1.代码随想录解法:左子树添加到右子树最左边,返回删除节点右孩子为新的当前根节点
class Solution {public TreeNode deleteNode(TreeNode root, int key) {//分为五种情况:// 1.未找到,直接返回rootif (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
,其中元素已经按 升序 排列,请你将其转换为一棵平衡二叉搜索树。
链接:108. 将有序数组转换为二叉搜索树
代码:
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
的值之和。
链接: 538. 把二叉搜索树转换为累加树
代码:
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);}
}