代码随想录算法训练营
Day21 代码随想录算法训练营第 21天 |LeetCode669. 修剪二叉搜索树 LeetCode108.将有序数组转换为二叉搜索树 LeetCode 538.把二叉搜索树转换为累加树
目录
前言
LeetCode669. 修剪二叉搜索树
LeetCode108.将有序数组转换为二叉搜索树
LeetCode 538.把二叉搜索树转换为累加树
一、LeetCode669. 修剪二叉搜索树
1.题目链接
2.思路
(1)注意:删除节点是不可以直接将节点赋值为NULL
(2)递归思路:
1)遇到空节点:返回
2)当前节点root的值大于上限:
①右子树节点一定都大于上限,所以用左子结点顶替当前节点;
②左子结点是左子树递归调用函数的返回值,所以将左子树递归调用函数的返回值赋值给当前节点;
③当前节点已经确定,返回。
3)当前节点root的值小于下限:
①左子树节点一定都小于下限,所以用有子结点顶替当前节点
②右子结点是右子树递归调用函数的返回值,所以将右子树递归调用函数的返回值赋值给当前节点;
③当前节点已经确定,返回。
4)当前节点root的值在区间中:
节点不动,去确定节点的左右子节点。
右子结点是右子树递归调用函数的返回值,左子结点是左子树递归调用函数的返回值
3.题解
class Solution {
public:
TreeNode* parent;
TreeNode* trimBST(TreeNode* root, int low, int high) {
if (root == NULL)
return root;
if (root->val > high) {
root->right = NULL;
root = trimBST(root->left, low, high);
return root;
}
if (root->val < low) {
root = trimBST(root->right, low, high);
return root;
}
root->left = trimBST(root->left, low, high);
root->right = trimBST(root->right, low, high);
return root;
}
};
二、LeetCode108.将有序数组转换为二叉搜索树
1.题目链接
2.思路
(1)平衡二叉搜索树:
1)平衡:子树高度差不超过1,所以根节点是最中间的节点
2)二叉搜索树:
中间节点左边的数组中所有数都小于中间节点,生成左子树;中间节点邮编的数组中所有数都大于中间节点,生成右子树
(2)递归
1)返回值:节点指针
参数:数组,闭区间左右端点
2)边界
l>r,区间无效,返回空
l==r,只有一个节点,返回刚刚制作的节点
3)单层递归
① 取出最中间的值:nums[(r - l) / 2 + l],作为子树根节点
(这种写法可以防止超出int)
② 创建节点,作为子树的根节点
③ 如果l等于r,说明子树只有一个节点,返回
④节点的左子节点为左侧子数组递归调用返回值,节点的右子节点为右侧子数组递归调用返回值
⑤ 返回子树根节点
3.题解
class Solution {
public:
TreeNode* build_BST(vector<int>& nums, int l, int r) {
if (l > r)
return NULL;
int val = nums[(r - l) / 2 + l];
TreeNode* node = new TreeNode(val);
if (l == r)
return node;
node->left = build_BST(nums, l, (l + r) / 2 - 1);
node->right = build_BST(nums, (l + r) / 2 + 1, r);
return node;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
int n = nums.size();
return build_BST(nums, 0, n - 1);
}
};
三、LeetCode 538.把二叉搜索树转换为累加树
1.题目链接
2.思路
(1)每个节点的新值(累加和)等于节点原值加右子节点新值:
因为右子节点是大于节点的最小节点,与右子节点相比,大于等于节点的数只多了节点自身的原值
(2)为什么从右向左求,而不是从左向右
1)最右侧的节点为最大节点,新值(累加和)就是原来的值,所以已知;
2)每个节点的新值(累加和)等于左子节点新值减去节点原值,理论上也可以从左向右,但是最左侧节点的累加和是所有节点原来值的总和,不易求
3.题解
class Solution {
public:
int pre = 0;
void in_order(TreeNode* node) {
if (node == NULL)
return;
in_order(node->right);
node->val += pre;
pre = node->val;
in_order(node->left);
}
TreeNode* convertBST(TreeNode* root) {
if (root == NULL)
return root;
in_order(root);
return root;
}
};
总结
1、对递归有了更深入的认识
(1)今天修建二叉树的递归相当于对子树进行修建,返回子树根节点
(2)在写递归的时候,将递归调用假想成已经实现的功能
(3)返回空还是节点指针
获取前中后序数组:返回空
增删节点:返回节点
其实有的时候一道题既可以返回空,也可以返回节点指针
2、二叉树题型总结
(1)二叉树的遍历:
1)深度优先:前序,中序,后序
2)广度优先:层序遍历
(2)二叉树的属性
1)深度:从根节点出发,经过多少节点-----前序
2)高度:从最底层出发,经过多少节点----后序
3)路径:前序
4)利用左右子节点的返回值求当前节点的属性-----后序
(3)二叉树的修改和构造
1)翻转
2)数组构造
3)合并
(4)二叉搜索树的属性:中序,利用有序性
(5)二叉搜索树的修改和构造
1)插入:递归搜索+节点插入(返回值为节点指针)
2)删除
3)修剪
4)构造平衡二叉搜索树
(6)公共祖先
1)二叉树最近公共祖先:后序,回溯(由于要对左右子节点进行判断,所以先进行左和右)
2)二叉搜索树最近公共祖先:第一个在区间内的
3、前中后序的选择
- 涉及到二叉树的构造,前序,先构造中节点
- 求普通二叉树的属性,一般是后序
后序一般是要通过递归函数的返回值做当前节点(中)计算
求深度也会用前序
- 求二叉搜索树的属性,中序(也可以是反转的中序)