669.修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树
669.修剪二叉搜索树
给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。
思路:递归法
遍历二叉树过程中,判断结点的值。如果在区间内,继续递归。如果不在区间内分成两种情况
第一种情况:当前结点val小于区间最小值。那结点的左子树不用考虑。结点的右子树可能存在符合条件的值,所以对结点的右子树处理,最后返回符合条件的右子树根节点
第二种情况:当前结点的val大于区间最大值。那结点的右子树不用考虑,结点的左子树可能存在符合条件的值,所以对结点的左子树处理,最后返回符合条件的左子树根结点
那么理解了核心逻辑,开始递归法三要素
1.方法入参和返回值: 入参 root根节点 low high 返回值 TreeNode
因为遍历的树是整个树,我们知道根节点root,没有返回值也可以。有返回值的目的是为了方便递归
2.中止条件
当遍历到空姐点时,结束递归
3.核心逻辑
如果当前结点root的值小于区间最小值,那么递归root右子树,返回符合条件的右子树根节点
if (root.val < low) {
return travel(root.right,low,high);
}
如果当前结点root的值大于区间最大值,那么递归root左子树,返回符合条件的左子树根节点
if (root.val > high) {
return travel(root.left,low,high);
}
接下来将下一层处理完结果赋值给root.left和root.right,并返回root
root.left = travel(root.left, low, high);
root.right = travel(root.right, low, high);
return root;
代码如下
// 时间复杂度o(n)
// 空间复杂度o(n)
public static TreeNode trimBST(TreeNode root, int low, int high) {
return travel(root, low, high);
}
public static TreeNode travel(TreeNode root, int low, int high) {
if (root == null)
return null;
if (root.val > high) {
return travel(root.left,low,high);
}
if (root.val < low) {
return travel(root.right,low,high);
}
root.left = travel(root.left, low, high);
root.right = travel(root.right, low, high);
return root;
}
108.将有序数组转换为二叉搜索树
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
思路:递归法
108.将有序数组转换为二叉搜索树
一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1
因为数组升序排序
那么当数据元素为奇数,根节点只可能为最中间的结点。比如【-1,0,1,2,3】根节点为1
那么当数组元素为偶数,根节点只可能为最中间的两个结点。比如【-1,0,1,2】根节点为0,1.
递归法三要素
1.方法入参和返回值。入参:int[] nums 返回值TreeNode root
2.中止条件:数组的长度小于等于0,返回Null
3.核心逻辑
判断数组长度奇偶
长度为奇数,取最中间结点作为根节点,拆分左右数组
长度为偶数,取最中间结点中靠左或者靠右(这里为了保证左闭右开),拆分左右数组
对左右数组递归,root.left = 左数组返回结果,root.right = 右数组返回结果
返回root
代码如下
// 时间复杂度o(n)
// 空间复杂度o(n)
public TreeNode sortedArrayToBST(int[] nums) {
return travel(nums);
}
public TreeNode travel(int[] nums) {
if (nums.length <= 0) {// 中止条件
return null;
}
TreeNode root;
int[] leftNums;
int[] rightNums;
int index = (nums.length - 1) / 2;
root = new TreeNode(nums[index], null, null);// 核心逻辑
if (nums.length % 2 == 1) {
leftNums = new int[index];
rightNums = new int[index];
} else {
leftNums = new int[index];
rightNums = new int[index + 1];
}
for (int i = 0; i < nums.length; i++) {
if (i < index)
leftNums[i] = nums[i];
if (i > index)
rightNums[i - index - 1] = nums[i];
}
root.left = travel(leftNums);
root.right = travel(rightNums);
return root;
}
思路:递归法优化
构造二叉树的时候尽量不要重新定义左右区间数组,而是用下标来操作原数组。
所以代码如下:TreeNode* traversal(vector& nums, int left, int right)
确定递归终止条件
这里定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点了。
代码如下:
if (left > right) return null;
取数组中间元素的位置,不难写出int mid = (left + right) / 2;,这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在二分法 (opens new window)中尤其需要注意!
所以可以这么写:int mid = left + ((right - left) / 2);
代码如下
// 时间复杂度o(n)
// 空间复杂度o(n)
public TreeNode sortedArrayToBST(int[] nums) {
TreeNode root = traversal(nums, 0, nums.length - 1);
return root;
}
// 左闭右闭区间[left, right]
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],null,null);
root.left = traversal(nums, left, mid - 1);
root.right = traversal(nums, mid + 1, right);
return root;
}
538.把二叉搜索树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。 节点的右子树仅包含键 大于 节点键的节点。 左右子树也必须是二叉搜索树。
示例 1:
- 输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
- 输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
示例 2:
- 输入:root = [0,null,1]
- 输出:[1,null,1]
示例 3:
- 输入:root = [1,0,2]
- 输出:[3,3,2]
示例 4:
- 输入:root = [3,2,4,1]
- 输出:[7,9,4,10]
提示:
- 树中的节点数介于 0 和 104 之间。
- 每个节点的值介于 -104 和 104 之间。
- 树中的所有值 互不相同 。
- 给定的树为二叉搜索树。
思路:递归法(右中左)
这题目不好理解。将二叉搜索树中序遍历后的数组列出来,方便理解【1,2,3,4,5,6】
如果从数组的角度来说,这道题将数组从尾部做累加,双指针法即可。
找到二叉搜索树的某个结点比如说3,
比3大的值有4,5,6.
构建后的3结点值变更为3+4+5+6=18
那么数组大家都会,放到树上也是一个道理
我们定义pre指针保存树遍历的上一个结点val,遍历当前结点cur时,将结点的值做累加即可
遍历顺序为特殊的中序遍历(右中左)。因为这样才能保证遍历的结点顺序是由大到小
代码如下
// 时间复杂度o(n)
// 空间复杂度o(n)
int pre = 0;
public TreeNode convertBST(TreeNode root) {
travel(root);
return root;
}
public void travel(TreeNode cur){
if(cur == null)
return;
travel(cur.right);
if(pre != 0)
cur.val = cur.val +pre;
pre = cur.val;
travel(cur.left);
return;
}