669. 修剪二叉搜索树
力扣题目链接
题目描述:
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
示例 1:
输入:root = [1,0,2], low = 1, high = 2
输出:[1,null,2]
思路:
- 递归法,这道题递归法比较简单,采用中序遍历,如果跟节点值比
low
小,证明区间在树的右子树上,就往右走,如果跟节点值比high
大,说明区间在左子树上,就往左走,如果根节点恰好在区间里,那么就把根节点不动,去分别递归左右子树,返回的结果接在根节点的左右指针上就行。 - 递归三部曲:
- 确定函数参数和返回值:函数参数就是根节点和
low
和high
,返回值为根节点 - 函数退出条件:根节点为空的时候
- 单步处理逻辑:当
root->val > high
时,递归左子树,当root->val < low
时,递归右子树,当在区间内时,就分别递归左右子树然后返回值接到root
的左右就好。
- 确定函数参数和返回值:函数参数就是根节点和
代码实现:
TreeNode* traversal(TreeNode* root, int low, int high) {
if (root == nullptr) return nullptr;
if (root->val > high) return traversal(root->left, low, high);
if (root->val < low) return traversal(root->right, low, high);
root->left = traversal(root->left, low, high);
root->right = traversal(root->right,low, high);
return root;
}
TreeNode* trimBST(TreeNode* root, int low, int high) {
return traversal(root, low, high);
}
- 迭代法:本题迭代法比较绕,大体思路和递归法类似的,先找到根节点,然后对根节点的左右子树做剪枝(其实递归法也是这个逻辑,前两个判断不就是在找根节点嘛!!!,找到了再对左右子节点做剪枝)。
- 步骤如下:
- 第一:先找合适的根节点,当根节点比区间最小值还要小就到右子树去找
root
,如果比最大值还要大,那就到左子树上去找root
,直到root
在[low,high]
里了(注意是闭区间) - 找到
root
后,对左右子树进行剪枝,因为左子树上可能有比low
小的,右子树上可能有比high
大的。 - 怎么剪枝?
- 剪左子树的时候,我们要剪掉比
low
小的,那么就去判断cur的左子树是不是比low小,如果比low小,那么它左子树的左子树就都剪掉了,把左子树的右子树接到cur到左子树上,此时cur的左子树已经更新,然后继续对cur的左子树判断,直到全部遍历完。 - 剪右子树和左子树一样的逻辑,去找cur的右子树,只要比high大,就把右子树的左子树接到cur的右子树上,依此类推。
- 剪左子树的时候,我们要剪掉比
- 第一:先找合适的根节点,当根节点比区间最小值还要小就到右子树去找
代码实现:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (root == nullptr) return nullptr;
//找合适的根节点
while (root && (root->val < low || root->val > high)) {
if (root->val < low) {
root = root->right;
} else {
root = root->left;
}
}
TreeNode* cur = root; //把根节点存起来,做完剪枝返回root,这里用cur去遍历
//剪枝左子树
while (cur) {
while(cur->left && cur->left->val < low) {
cur->left = cur->left->right;
}
cur = cur->left;
}
//剪枝右子树
cur = root;//回溯到root用于遍历右子树
while (cur) {
while(cur->right && cur->right->val > high) {
cur->right = cur->right->left;
}
cur = cur->right;
}
return root;
}
108.将有序数组转换为二叉搜索树
力扣题目链接
题目描述:
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
示例 1:
输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9]
思路:
- 构造一棵树,先找根节点,然后再找左右节点,接到根节点上就行,利用平衡二叉搜索树的性质,正好数组有序,我们每次取数组的中间元素作为根节点,然后递归左右子区间就好了。
- 递归三部曲:
- 确定函数参数和返回值:函数参数为数组nums和区间的起始位置和结束位置(注意左闭右开还是左闭右闭,循环不变量!!!,很重要)
- 函数退出条件:当用左闭右开时begin大于等于end时退出,左闭右闭时,begin大于end时退出。
- 单步处理逻辑,取begin和end的中间值作为根节点,然后取递归左右子区间,把返回值接到root上即可。
代码实现
TreeNode* traversal(vector<int>& nums, int begin, int end) {
if (begin > end) return nullptr;
int root_index = begin + (end - begin) / 2;
TreeNode* root = new TreeNode(nums[root_index]);
root->left = traversal(nums, begin, root_index - 1);
root->right = traversal(nums, root_index + 1, end);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return traversal(nums, 0, nums.size() - 1);
}
538.把二叉搜索树转换为累加树
力扣题目链接
题目描述:
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
注意:本题和 1038: https://leetcode-cn.com/problems/binary-search-tree-to-greater-sum-tree/ 相同
示例 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]
思路:
- 递归法:这道题不用改变树结构,直接在遍历树的时候操作即可,和二叉搜索树的众数、二叉搜索树最小绝对值差 两道题差不多。
- 这里还是采用中序遍历,但是需要变一下,因为本题需要把每个节点值改为大于它的所有节点的值之和,而普通的中序遍历得到的是升序,我们得到的是比当前节点小的节点值之和,其实我们交换一下中序遍历左右子树的递归顺序,就得到的降序了,这样访问过的节点都是比自己大的节点了,剩下就很简单了,看代码!。
代码实现
int pre = 0;
void traversal(TreeNode* root) {
if (root == nullptr) return;
traversal(root->right);
root->val += pre;//pre初始为0,
/*后序都是前一个节点的值了,因为前一个节点已经更新了,
所以不用记录前面节点之和了)*/
pre = root->val;
traversal(root->left);
}
TreeNode* convertBST(TreeNode* root) {
if (root == nullptr) return nullptr;
traversal(root);
return root;
}
- 迭代法:套用中序遍历的模版就行,但是需要交换一下左右遍历顺序
代码实现:
TreeNode* convertBST(TreeNode* root) {
if (root == nullptr) return nullptr;
stack<TreeNode*> stk;
TreeNode* cur = root;
int pre = 0;
while (cur || !stk.empty()) {
if (cur) {
stk.push(cur);
cur = cur->right;
} else {
cur = stk.top();
cur->val += pre;
pre = cur->val;
stk.pop();
cur = cur->left;
}
}
return root;
}