目录
【669. 修剪二叉搜索树】中等题(偏简单)
方法一 递归
思路:关键是看是否需要更换根节点
- 如果根节点在区间内,则根节点不需要更换。
- 如果根节点不在区间内,则区间就在根节点的左子树或者右子树,需要更换根节点(相当于把根节点修剪掉),返回对应子树的修剪结果。
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) return null;
// 如果当前节点在区间内,则当前节点还是根节点
if (root.val >= low && root.val <= high){
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
// 如果当前节点不在区间内,则判断区间在当前节点的左子树还是右子树内,挑选新的根节点的剪枝结果
else{
// 如果区间在左子树上
if (root.val > high){
return trimBST(root.left, low, high);
}
// 如果区间在右子树上
else{
return trimBST(root.right, low, high);
}
}
}
}
方法二 迭代法(有点抽象,不建议)
思路:
1、确定最后要返回的根节点在区间内
2、在根节点一定在区间内的前提下,对左右子树剪枝
- 对左子树剪枝,左子树的所有节点都小于high,只需要判断左节点的val值是否小于low,令左节点位于区间内(>=low),再继续往左遍历
- 对右子树剪枝,右子树的所有节点都大于low,只需要判断右节点的val值是否大于high,令右节点位于区间内(<=high),再继续往右遍历
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
// 1、确定最后要返回的根节点
while (root != null && (root.val < low || root.val > high)){
// 能进循环的要么小于区间,要么大于区间,不可能等于
if (root.val < low) root = root.right;
else root = root.left;
}
// 2、在根节点一定在区间内的前提下,剪枝
// 2.1、对左子树剪枝,左子树的所有节点都小于high,只需要判断是否小于low
TreeNode cur = root;
while (cur != null){
// 如果左节点的值小于low,证明左节点以及左节点的左子树都小于low,要剪掉,继续判断左节点的右子树即可
while (cur.left != null && cur.left.val < low){
cur.left = cur.left.right;
}
// 现在的左节点大于等于low,则继续往左遍历
cur = cur.left;
}
// 2.2、对右子树剪枝,右子树的所有节点都大于low,只需要判断节点是否大于high
cur = root;
// 如果右节点的值大于high,证明右节点以及右节点的的右子树都大于high,要剪掉,继续判断右节点的左子树即可
while (cur != null){
while (cur.right != null && cur.right.val > high){
cur.right = cur.right.left;
}
// 现在的右节点小于等于high,则继续往右遍历
cur = cur.right;
}
return root;
}
}
【108.将有序数组转换为二叉搜索树】简单题
方法 递归
思路:获取中间/靠近中间的节点,划分左右子树对应区间,分别构建平衡的左右子树。
相似题目:106.从中序与后序遍历序列构造二叉树
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return makeBST(nums, 0, nums.length);
}
// 左闭右开
public TreeNode makeBST(int[] nums, int start, int end){
if (start == end) return null;
// 构建平衡二叉树的关键是选中间/靠近的节点作为根节点
int mid = (end - 1 + start) / 2;
TreeNode root = new TreeNode(nums[mid]);
// 构建左右子树
root.left = makeBST(nums, start, mid);
root.right = makeBST(nums, mid+1, end);
return root;
}
}
【538.把二叉搜索树转换为累加树】中等题
思路:巧妙利用pre节点记录上一个遍历的节点
方法一 递归 - 中序遍历的倒序
思路:按中序的倒序求和,pre记住上个节点的值,pre不为null时当前节点的值叠加pre节点的值即可,原地修改原二叉树为累加树
class Solution {
TreeNode pre = null;
public TreeNode convertBST(TreeNode root) {
// 按中序的倒序求和:pre记住上个节点的值,pre不为null时当前节点的值叠加pre节点的值即可
if (root == null) return null;
// 先更新右子树的值
root.right = convertBST(root.right);
// 再更新当前节点的值
if (pre != null) root.val += pre.val;
pre = root;
// 最后更新左子树的值
root.left = convertBST(root.left);
return root;
}
方法二 统一迭代法 - 中序遍历的倒序
思路:中序遍历的倒序(右中左)的入栈顺序为【cur.left -> cur -> null -> cur.right】,处理节点的时候也是pre不为null时,当前节点的val加上pre的val,更新pre。
class Solution {
public TreeNode convertBST(TreeNode root) {
Deque<TreeNode> stack = new LinkedList<>();
if (root == null) return null;
TreeNode cur = root;
stack.push(cur);
TreeNode pre = null;
while(!stack.isEmpty()){
cur = stack.pop();
if (cur != null) {
if (cur.left != null) stack.push(cur.left);
stack.push(cur);
stack.push(null);
if (cur.right != null) stack.push(cur.right);
}
else{
cur = stack.pop();
if (pre != null) cur.val += pre.val;
pre = cur;
}
}
return root;
}
}
二叉树总结
参考代码随想录的【二叉树总结】