第一题:669. 修剪二叉搜索树
解题思路
- 整体思路:
- 要对给定的二叉搜索树进行修剪,使其所有节点的值都落在指定的区间
[low, high]
内,并且要保留树中原有的节点相对结构。利用二叉搜索树节点值大小的特性(左子树节点值小于根节点值,右子树节点值大于根节点值)来递归地判断和修剪每个节点。 - 通过不断递归遍历树的节点,根据节点值与给定边界
low
和high
的比较情况,来决定是保留、舍弃还是继续递归处理该节点及其子树部分。
- 要对给定的二叉搜索树进行修剪,使其所有节点的值都落在指定的区间
- 具体步骤:
- 基础情况判断:首先判断传入的根节点
root
是否为空,如果为空,直接返回null
,表示已经遍历到树的底部或者本身就是空树,无需进行修剪操作了。 - 节点值小于下限情况:若当前根节点
root
的值小于给定的下限low
,根据二叉搜索树的特性,其左子树所有节点值肯定也都小于low
,所以整棵左子树都不符合要求,应该舍弃,直接返回对右子树进行修剪后的结果(通过递归调用trimBST(root.right, low, high)
),也就是去处理右子树部分,看右子树中哪些节点是符合区间要求可以保留的。 - 节点值大于上限情况:若当前根节点
root
的值大于给定的上限high
,同理,其右子树所有节点值肯定也都大于high
,右子树不符合要求应舍弃,直接返回对左子树进行修剪后的结果(通过递归调用trimBST(root.left, low, high)
),去检查左子树中有哪些节点能保留下来。 - 节点值在区间内情况:当根节点
root
的值在[low, high]
这个区间内时,说明当前根节点是符合要求可以保留的,那就需要继续对它的左子树和右子树分别进行递归修剪,将修剪好的左子树重新赋值给root.left
,修剪好的右子树赋值给root.right
,最后返回这个经过处理后的根节点root
,代表当前子树修剪完成,向上一层返回修剪好的部分。
- 基础情况判断:首先判断传入的根节点
代码
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在[low,high]范围内
root.left = trimBST(root.left,low,high);
root.right = trimBST(root.right,low,high);
return root;
}
}
第二题:108.将有序数组转换为二叉搜索树
解题思路
- 整体思路:
- 题目要求把一个升序排列的整数数组转换为一棵平衡二叉搜索树。平衡二叉搜索树的特点是左右子树的高度差绝对值不超过 1,且满足二叉搜索树节点值大小的特性(左子树节点值小于根节点值,右子树节点值大于根节点值)。我们可以利用数组已排序的特性,通过选取合适的中间元素作为根节点,然后递归地构建左右子树来实现转换。
- 具体步骤:
- 基础情况判断:
- 在
sortedArrayToBST1
方法中,首先判断传入的区间范围是否满足结束条件。如果left >= right
,意味着这个区间内已经没有元素或者只有一个元素已经处理完了,这时候返回null
,表示对应子树为空。 - 另外,如果
right - left == 1
,说明区间内只剩下一个元素了,那就直接以这个元素创建一个新的树节点并返回,这个节点就是对应子树的根节点,它没有左右子树(因为只剩这一个元素了)。
- 在
- 选取根节点:计算区间
[left, right)
的中间元素的下标mid
,通过公式left + (right - left) / 2
来获取(这样可以避免整数溢出问题,相较于(left + right) / 2
更安全)。然后以这个中间元素nums[mid]
作为当前子树的根节点,创建一个新的TreeNode
对象。 - 构建左右子树:
- 对于根节点的左子树,通过递归调用
sortedArrayToBST1
方法,传入左半区间[left, mid)
,这样就能基于左半区间的元素构建出平衡的左子树,并将构建好的左子树赋值给根节点的left
属性。 - 同理,对于右子树,传入右半区间
[mid + 1, right)
进行递归调用,构建出右子树后赋值给根节点的right
属性。
- 对于根节点的左子树,通过递归调用
- 返回根节点:最后返回构建好的整个子树的根节点,随着递归的层层返回,最终就构建出了完整的平衡二叉搜索树。
- 基础情况判断:
代码
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return sortedArrayToBST1(nums,0,nums.length);
}
public TreeNode sortedArrayToBST1(int[] nums, int left,int right){
if(left >= right){
return null;
}
if(right - left == 1){
return new TreeNode(nums[left]);
}
int mid = left + (right - left) / 2;
TreeNode root = new TreeNode(nums[mid]);
root.left = sortedArrayToBST1(nums,left,mid);
root.right = sortedArrayToBST1(nums,mid + 1,right);
return root;
}
}
第三题:538.把二叉搜索树转换为累加树
解题思路
- 目标明确:题目要求将给定的二叉搜索树转换为累加树,也就是要让树中每个节点的新值等于原树中大于或等于该节点值的所有值之和。
- 利用二叉搜索树特性:由于二叉搜索树的节点左子树的值都小于当前节点值,右子树的值都大于当前节点值。我们可以利用这个特性来确定节点值的累加顺序。如果按照常规的先序、中序、后序遍历(中左右、左中右、左右中)都不太容易直接实现题目要求,因为常规顺序很难方便地获取到当前节点右侧那些比它大的值的总和。
- 选择合适遍历顺序:而采用右中左的遍历顺序(也就是反中序遍历),就能先遍历到比当前节点值大的右子树部分,先把这些较大值进行累加,然后再处理当前节点(将累加和赋值给当前节点的新值),最后再去处理左子树部分,这样就能符合题目中每个节点新值等于大于或等于其值的所有值之和的要求了。
- 递归实现:使用递归的方式来实现这种右中左的遍历,递归遍历整个二叉搜索树,在遍历的过程中逐步更新节点的值来构建累加树。
代码
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在[low,high]范围内
root.left = trimBST(root.left,low,high);
root.right = trimBST(root.right,low,high);
return root;
}
}