所用代码 java
修剪二叉树 LeetCode 669
题目连接:修剪二叉树 LeetCode 669 - 中等
思路
本题是前面删除二叉树的结点那题的一个进阶版。删除边界的值的话肯定有一个最大边界,一个最小边界,删除的数可能是多个的。
递归法:
若结点值在边界之外,删除的情况有两种:
- 结点值小于low,那就去
递归结点的右孩子(因为左孩子肯定小于low)
,右孩子中也有可能小于low的,所以应把该结点再次进行递归 - 结点值大于high,就
递归左孩子(因为右孩子肯定大于high)
,但是左孩子也有可能大于high,就继续往左递归,返回正确构建好的二叉树
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
return traversal(root, low, high);
}
public TreeNode traversal(TreeNode root, int low, int high){
if (root == null) return null;
// 结点值小于low,就去递归右孩子
if (root.val < low){
return traversal(root.right, low, high);
}
// 结点值大于high,就去递归左孩子
if (root.val > high){
return traversal(root.left, low, high);
}
// 若root不在区间之类,返回的就是他的左右孩子
// 因为最前面已经判断root的值和low与high大小关系了
root.left = traversal(root.left, low, high);
root.right = traversal(root.right, low, high);
// 返回删除好的二叉搜索树
return root;
}
}
迭代法:
- 将root移至[low, high]区间 –
左闭右闭
- 修剪左子树,
左子树的值一定是小于high
,就只用修剪小于low的值 - 修剪右子树,
同理右子树的值一定大于low
,所以只用考虑大于high的值
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) return null;
// 1、将root移动到[low, high]区间
while (root != null &&(root.val < low || root.val > high)){
// 小于low往右走,大于low则往左走
if (root.val < low) root = root.right;
else root = root.left;
}
// 由于root在low和high之间,
// 左边的值可能会小于low,但是左边的值一定小于high,不用考虑大于high的情况
// 同理,右边的值一定是大于low的
TreeNode cur = root; // 处理右边的指针
// 2、修剪左区间 -- 左边就只用考虑小于low的情况
while (cur != null){
while (cur.left != null && cur.left.val < low){
cur.left = cur.left.right;
}
cur = cur.left;
}
cur = root; // 处理右边的指针
// 3、修剪右区间
while (cur != null){
while (cur.right != null && cur.right.val > high){
cur.right = cur.right.left;
}
cur = cur.right;
}
return root;
}
}
总结
本题看似简单,就是删除结点值,但是和上一题不同。因为本题需删除区间外的值,不是简单删除一个值,需递归的把不需要的结点给删除掉。
将有序数组转换为二叉搜索树 LeetCode 108
题目连接:将有序数组转换为二叉搜索树 LeetCode 108 - 简单
思路
这题属于构建二叉树的题目,由于数组是有序的,那么他的根结点就是数中间的那个值,然后我们以此递归构建二叉树。且该二叉树一定是平衡二叉树,因为左右结点的个数是相同的
递归:
- 找到根结点 – 数组的中间的值
- 以该值划分左右区间 ( 左右下标可以直接操作数组 )
- 递归构建二叉树
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return traversal(nums);
}
public TreeNode traversal(int[] nums){
if (nums.length == 0) return null;
// 以中间的值为根结点
int rootValue = (nums[nums.length/2]);
TreeNode root = new TreeNode(rootValue);
// 只有一个结点 直接返回
if (nums.length == 1) return root;
// 切分左右子树区间 copyOfRange -- 左闭右开
int[] left = Arrays.copyOfRange(nums, 0, nums.length/2);
int[] right = Arrays.copyOfRange(nums, nums.length/2 + 1, nums.length);
root.left = traversal(left);
root.right = traversal(right);
return root;
}
}
由于数组可以直接用下标来操作,上边的代码可以进行优化,不用定义新的数组,节省空间:
直接用数组的下标来操作:左闭右开
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return traversal(nums, 0 , nums.length);
}
public TreeNode traversal(int[] nums, int begin, int end){
if (begin == end) return null;
// 以中间的值为根结点
int mid = (begin + end) / 2; // 这里是下标相加,不用担心爆内存
int rootValue = (nums[mid]);
TreeNode root = new TreeNode(rootValue);
// 只有一个结点就之间返回
if (end - begin == 1) return root;
root.left = traversal(nums, begin, mid);
root.right = traversal(nums, mid+1, end);
return root;
}
}
总结
只要清楚单调递增的数组,用中间的点为根结点,左边为左子树,右边为右子树,那我们就可以很轻松的构建出二叉搜索树,且该树一定是平衡二叉树。
把二叉搜索树转换为累加树 LeetCode 538
题目链接:把二叉搜索树转换为累加树 LeetCode 538 - 中等
思路
无。没看懂题。。。。
该题的意思是,二叉树的某个结点的值为:比该结点大的所有值相加
一种容易看懂的暴力解法:
class Solution {
List<Integer> list;
public TreeNode convertBST(TreeNode root) {
list = new ArrayList<>();
sumOfTree(root, list);
traversal(root);
return root;
}
// 构建累加树
public void traversal(TreeNode node){
if (node == null) return;
node.val = newVal(node.val);
traversal(node.left);
traversal(node.right);
}
// 二叉搜索树中序 => 从小到大递增
public void sumOfTree(TreeNode node, List<Integer> list){
if (node == null) return;
sumOfTree(node.left, list);
list.add(node.val);
sumOfTree(node.right, list);
}
// 求比该结点大的值的和
public int newVal(int val){
int sum = 0;
for (Integer i : list) {
if (val <= i) {
sum += i;
}
}
return sum;
}
}
其实双指针进行递归,可以一次递归就完成赋值加求和:
且二叉搜索树以中序(左 中 右 )为单调递增的树,所有我们可以反过来遍历(右 中 左)
,从大到小的进行累加:
class Solution {
int pre;
public TreeNode convertBST(TreeNode root) {
pre = 0;
traversal(root);
return root;
}
public void traversal(TreeNode node){
if (node == null) return;
traversal(node.right); // 右
node.val += pre; // 中
// 再把该指针往上移
pre = node.val;
traversal(node.left); // 左
}
}
另外,本题使用迭代法也非常简单,其迭代法就是中序遍历的模板,但是我们是以右 中 左
的顺序进行的
迭代法:
class Solution {
public TreeNode convertBST(TreeNode root) {
Stack<TreeNode> stack = new Stack<TreeNode>();
// pre用于记录前一个数值
int pre = 0;
TreeNode cur = root;
while (cur != null || !stack.isEmpty()){
if (cur != null){
stack.push(cur);
cur = cur.right; // 右
}else {
// 中
cur = stack.pop();
cur.val += pre;
pre = cur.val;
// 左
cur = cur.left;
}
}
return root;
}
}
总结
本题就是一个双指针的题,关键在于如何进行遍历,使二叉搜索树单调递减排序,然后我们就可以从后往前累加他的值了。