题目:
给你二叉搜索树的根节点
root
,同时给定最小边界low
和最大边界high
。通过修剪二叉搜索树,使得所有节点的值在[low, high]
中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
示例 1:
输入:root = [1,0,2], low = 1, high = 2 输出:[1,null,2]示例 2:
输入:root = [3,0,4,null,2,null,null,1], low = 1, high = 3 输出:[3,2,null,1]提示:
- 树中节点数在范围
[1, 10^4]
内0 <= Node.val <= 10^4
- 树中每个节点的值都是 唯一 的
- 题目数据保证输入是一棵有效的二叉搜索树
0 <= low <= high <= 10^4
[LeetCode] 669. 修剪二叉搜索树
自己看到题目的第一想法
1. 遍历二叉树, 遇到不符合的节点, 则删除该节点.
看完代码随想录之后的想法
一开始我删除节点的时候, 使用后续遍历, 从叶子结点开始处理, 一个一个递归上去. 然而这样就无法利用到二叉搜索树的特性: 如果当前节点不在范围内, 那他的左子树或者右子树, 有一个就一定不在范围内.
// 递归法: 耗时版本.
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) {
return root;
}
root.left = trimBST(root.left, low, high);// 删除所有左子树中不合适的节点
root.right = trimBST(root.right, low, high);// 删除所有右子树中不合适的节点
// 确认一下当前节点是否满足条件.
// 如果当前节点不满足条件的话, 他的左子树或者右子树是不需要处理的.
// 然而这里用后续遍历的话, 递归过程中就要处理原本已知不满足条件的节点.
if (root.val < low) {
root = root.right;
} else if (root.val > high) {
root = root.left;
}
return root;
}
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) {
return root;
}
if (root.val < low) {
// 如果当前节点不满足条件, 则向下寻找满足条件的节点
// 这里的 return 会自动删除当前节点, 并寻找最近的合适的节点
return trimBST(root.right, low, high);
} else if (root.val > high) {
// 如果当前节点不满足条件, 则向下寻找满足条件的节点
// 这里的 return 会自动删除当前节点, 并寻找最近的合适的节点
return trimBST(root.left, low, high);
}
// 走到这里说明当前的节点是合适的, 但是要处理一下左右子节点
// 将左右子树中不合适的节点删除
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
// 迭代法
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) {
return null;
}
while (root != null && (root.val < low || root.val > high)) {
if (root.val < low) {
root = root.right;
} else {
root = root.left;
}
}
if (root == null) {
return null;
}
TreeNode node = root;
while (node.left != null) {
if (node.left.val < low) {
node.left = node.left.right;// 这里直接舍弃一半真的太舒服了
} else if (node.left.val > high) {
node.left = node.left.right;// 这里直接舍弃一半真的太舒服了
} else {
node = node.left;// 到这里说明 node.left 是满足条件的
}
}
node = root;
while (node.right != null) {
if (node.right.val < low) {
node.right = node.right.right;
} else if (node.right.val > high) {
node.right = node.right.left;
} else {
node = node.right;
}
}
return root;
}
}
自己实现过程中遇到哪些困难
一开始自己写的太乱了, 对于递归的执行顺序也没有想明白. 想了一堆没有用的逻辑. 后来简化完之后, 发现自己之前提交的代码, 可以通过删除代码得到简化的版本. 修建二叉树的逻辑看起来简单, 但是似乎自己并没有掌握得很好.
[LeetCode] 108. 将有序数组转换为二叉搜索树 文章解释
[LeetCode] 108. 将有序数组转换为二叉搜索树 视频解释
题目:
给你一个整数数组
nums
,其中元素已经按 升序 排列,请你将其转换为一棵平衡
二叉搜索树。示例 1:
输入:nums = [-10,-3,0,5,9] 输出:[0,-3,9,-10,null,5] 解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:示例 2:
输入:nums = [1,3] 输出:[3,1] 解释:[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。提示:
1 <= nums.length <= 10^4
-10^4 <= nums[i] <= 10^4
nums
按 严格递增 顺序排列
[LeetCode] 108. 将有序数组转换为二叉搜索树
自己看到题目的第一想法
去中间的值生成根节点, 然后往左右两边递归生成左右子树
看完代码随想录之后的想法
思路是一致的.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
// 迭代法: 利用三个栈, 分别记录每个节点对应的序列区间范围
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
if (nums == null) {
return null;
}
Stack<Integer> leftIndex = new Stack<>();
Stack<Integer> rightIndex = new Stack<>();
Stack<TreeNode> nodes = new Stack<>();
TreeNode node;
TreeNode root = new TreeNode(0);
nodes.push(root);
leftIndex.push(0);
rightIndex.push(nums.length - 1);
while (!nodes.isEmpty()) {
node = nodes.pop();
int left = leftIndex.pop();
int right = rightIndex.pop();
if (left <= right) {
int mid = left + ((right - left) >> 1);
node.val = nums[mid];
if (left <= mid - 1) {
node.left = new TreeNode();
leftIndex.push(left);
rightIndex.push(mid - 1);
nodes.push(node.left);
}
if (right >= mid + 1) {
node.right = new TreeNode();
leftIndex.push(mid + 1);
rightIndex.push(right);
nodes.push(node.right);
}
}
}
return root;
}
}
自己实现过程中遇到哪些困难
迭代法没想出来~ 看了解释以后就简单多了.
[LeetCode] 538. 把二叉搜索树转换为累加树 文章解释
[LeetCode] 538. 把二叉搜索树转换为累加树 视频解释
题目:
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点
node
的新值等于原树中大于或等于node.val
的值之和。提醒一下,二叉搜索树满足下列约束条件:
- 节点的左子树仅包含键 小于 节点键的节点。
- 节点的右子树仅包含键 大于 节点键的节点。
- 左右子树也必须是二叉搜索树。
注意:本题和
[LeetCode] 1038 相同(PS: 不是我想换行, 是编辑器强制的... 位了编辑这几个 link, 浪费了我好几分钟. 各种方式都尝试了... 真是无奈.)示例 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
和10^4
之间。- 每个节点的值介于
-10^4
和10^4
之间。- 树中的所有值 互不相同 。
- 给定的树为二叉搜索树。
[LeetCode] 538. 把二叉搜索树转换为累加树
自己看到题目的第一想法
用右中左的方式遍历. 递归或者迭代应该都可以.
看完代码随想录之后的想法
思路是一致的. 但是因为递归结束条件的不同, 我自己实现的版本代码写的有点啰嗦.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private int preNodeSum = 0;
public TreeNode convertBST(TreeNode root) {
if (root == null) {
return null;
}
convertBST(root.right);
root.val += preNodeSum;
preNodeSum = root.val;
convertBST(root.left);
return root;
}
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private TreeNode preNode = 0;
public TreeNode convertBST(TreeNode root) {
if (root == null) {
return null;
}
convertBST(root.right);
root.val += (preNodeSum == null ? 0: preNode.val);
preNode = root;
convertBST(root.left);
return root;
}
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
// 迭代法: 这一题用迭代法还是比较清爽和简单的. 套模板就可以了.
class Solution {
private TreeNode preNode = null;
public TreeNode convertBST(TreeNode root) {
Stack<TreeNode> nodes = new Stack<>();
TreeNode node = root;
while (node != null || !nodes.isEmpty()) {
if (node != null) {
nodes.push(node);
node = node.right;
} else {
node = nodes.pop();
if (preNode != null) {
node.val += preNode.val;
}
preNode = node;
node = node.left;
}
}
return root;
}
}
自己实现过程中遇到哪些困难
递归结束条件写复杂了, 导致代码很冗余. 看了视频后有种豁然开朗的感觉, 原来只要一般的代码量就够了呀!