给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。
示例 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]
个人思路:
递归法法三部曲
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
return trimBST_(root, low, high);
}
public TreeNode trimBST_(TreeNode root, int low, int high) {
if (root == null)
return null;
if (root.val < low)//只剩下左孩子可能在范围中,去左孩子中筛选返回
return trimBST_(root.right, low, high);
else if (root.val > high)//只剩下右孩子可能在范围中,去右孩子中筛选返回
return trimBST_(root.left, low, high);
//左右孩子均可能存在在范围的数,分别筛选再返回作为当前结点的左右孩子结点
root.left = trimBST_(root.left, low, high);
root.right = trimBST_(root.right, low, high);
return root;
}
}
题解中的迭代法:
因为二叉搜索树的有序性,不需要栈来模拟递归
三步:
难点:
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null)
return null;
//调整根节点
while (root != null && (root.val > high || root.val < low)) {
if (root.val > high)
root = root.left;
else if (root.val < low)
root = root.right;
}
//调整左子树(左子树的右子树必然符合条件
TreeNode node = root;
while (node != null) {
while (node.left != null && (node.left.val < low || node.left.val > high)) {
node.left = node.left.right;
}
node = node.left;
}
//调整右子树(右子树的左子树必然符合条件
node = root;
while (node != null) {
while (node.right != null && (node.right.val < low || node.right.val > high)) {
node.right = node.right.left;
}
node = node.right;
}
return root;
}
}
题目简介:
给你一个整数数组 nums
,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
示例 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] 都是高度平衡二叉搜索树。
个人思路:
和之前做过的某道题有点类似,大概思路就是切割数组
切割的时候,尤其注意边界问题的处理
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return build(nums);
}
public TreeNode build(int[] nums) {
if (nums.length == 0)
return null;
TreeNode node = new TreeNode(nums[nums.length / 2]);
node.left = build(Arrays.copyOfRange(nums, 0, nums.length / 2));
node.right = build(Arrays.copyOfRange(nums, nums.length / 2 + 1, nums.length));
return node;
}
}
题目简介:
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(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]
个人思路:
这是一棵二叉搜索树,根据题意,我们可以选择使用右 中 左遍历,这样遍历得到的便是从大到小的顺序。遍历过程中,我们要一直累加sum变量。
递归三部曲:
确定参数和返回值:均为结点
确定递归结束条件:结点为null
确定单层递归逻辑:修改结点值和累计sum值
root.val += sum;
sum = root.val;
class Solution {
public int sum = 0;
public TreeNode convertBST(TreeNode root) {
return build(root);
}
public TreeNode build(TreeNode root) {
if (root == null)
return null;
//右 中 左遍历,即从大到小的遍历,sum进行累加
root.right = build(root.right);
root.val += sum;
sum = root.val;
root.left = build(root.left);
return root;
}
}
题解解析:
整体思路差不多,但递归的返回值其实可以为null
关于返回值为void的情况:通常不需要调整树的结构,只需要改变结点的值即可
class Solution {
public int sum = 0;
public TreeNode convertBST(TreeNode root) {
build(root);
return root;
}
public void build(TreeNode root) {
if (root == null)
return;
//右 中 左遍历,即从大到小的遍历,sum进行累加
build(root.right);
root.val += sum;
sum = root.val;
build(root.left);
}
}
深度优先遍历
前中后序 (递归实现)
前中后序 (模拟栈实现)
// 中序遍历顺序: 左-中-右 入栈顺序: 左-右
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()){
if (cur != null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}
前中后序 (模拟栈并统一风格)
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> st = new Stack<>();
if (root != null) st.push(root);
while (!st.empty()) {
TreeNode node = st.peek();
if (node != null) {
st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
//只需要调整下面这三部分代码顺序即可改变遍历顺序
if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈)
if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈)
st.push(node); // 添加中节点
st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
} else { // 只有遇到空节点的时候,才将下一个节点放进结果集
st.pop(); // 将空节点弹出
node = st.peek(); // 重新取出栈中元素
st.pop();
result.add(node.val); // 加入到结果集
}
}
return result;
}
}
广度优先遍历
下面是分类题型总结,若未涉及某种方法等二刷再补上
求二叉搜索树的属性
二叉搜索树的插入操作
二叉搜索树的删除操作
修剪二叉搜索树
构造高度平衡二叉搜索树
二叉树的构造:一般是先序,先有双亲才有孩子
二叉树的属性:一般是后序,先得到返回值才能处理当前结点的要素
二叉搜索树:一定是中序,有序性要利用起来
二叉搜索树的插入操作
二叉搜索树的删除操作
修剪二叉搜索树
构造高度平衡二叉搜索树