654.最大二叉树
题目
给定一个不重复的整数数组 nums
。 最大二叉树 可以用下面的算法从 nums
递归地构建:
-
创建一个根节点,其值为
nums
中的最大值。 -
递归地在最大值 左边 的 子数组前缀上 构建左子树。
-
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums
构建的 最大二叉树 。
示例:
输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:
- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
- [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
- 空数组,无子节点。
- [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
- 空数组,无子节点。
- 只有一个元素,所以子节点是一个值为 1 的节点。
- [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
- 只有一个元素,所以子节点是一个值为 0 的节点。
- 空数组,无子节点。
提示:
-
1 <= nums.length <= 1000
-
0 <= nums[i] <= 1000
-
nums
中的所有整数 互不相同
思路
💡凡是构造二叉树的题目,都要用前序遍历
最大二叉树的构建过程如下:
-
确定递归函数的参数和返回值
- 参数就是传入的是存放元素的数组,返回该数组构造的二叉树的头结点,返回类型是指向节点的指针
-
确定终止条件
-
输入的数组大小一定是大于等于 1,所以不需要考虑小于 1 的情况。当递归遍历时,如果传入数组大小为 1,说明遍历到叶子节点
-
定义一个新的节点,把这个数组的数值赋给新的节点,然后返回这个节点。表示一个数组大小是 1 时,构造了一个新的节点,并返回
TreeNode* node = new TreeNode(0); if(nums.size() == 1){ node->val = nums[0]; return node; }
-
-
确定单层递归的逻辑
-
找到数组中最大的值和对应的下标,最大的值构造根节点,下标用来下一步分割数组
int maxValue = 0; int maxValueIndex = 0; for(int i = 0; i < nums.size(); ++i){ if(nums[i] > maxValue){ maxValue = nums[i]; maxValueIndex = i; } } TreeNode* node = new TreeNode(0); node->val = maxValue;
-
最大值所在的下标左区间,构造左子树。这里要判断 maxValueIndex > 0,因为要保证左区间至少有一个数值
if(maxValueIndex > 0){ vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex); node->left = constructMaximumBinaryTree(newVec); }
-
最大值所在的下标右区间,构造右子树。判断 maxValueIndex < (num.size() - 1),确保右区间至少有一个数值
if(maxValueIndex < (nums.size() - 1)){ vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end()); node->right = constructMaximumBinaryTree(newVec); }
-
代码实现
-
返回类型 TreeNode* construct(vec nums)
-
终止条件:
- if(num.size == 1)
- return new TreeNode(nums[0]);
- if(num.size == 1)
-
单层递归逻辑:
- 中:
- int maxValue = 0
- int index = 0
- for(int i = 0; i < nums.size(); i++){
- if(nums[i]>maxValue){
- maxValue = num[i];
- index = i
- if(nums[i]>maxValue){
- node = new TreeNode(maxValue)
- 左:
- if(index > 0)
- newVec(0, index); 左闭右开
- node->left = contruct(newVec);
- 右:
- if(index < nums.size-1)
- newVec(index+1, nums.size)
- node->right = contruct(newVec);
- return node;
优化:不要每次构造新的 vector,控制下标就好
class Solution {
private:
TreeNode* traversal(vector<int>& nums, int left, int right){
if(left >= right)return nullptr;
int maxValueIndex = left;
for(int i = left + 1; i < right; ++i){
if(nums[i] > nums[maxValueIndex]) maxValueIndex = i;
}
TreeNode* root = new TreeNode(nums[maxValueIndex]);
root->left = traversal(nums, left, maxValueIndex);
root->right = traversal(nums, maxValueIndex + 1, right);
return root;
}
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return traversal(nums, 0, nums.size());
}
};
617.合并二叉树
题目
给你两棵二叉树: root1
和 root2
。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
示例 1:
输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]
提示:
-
两棵树中的节点数目在范围
[0, 2000]
内 -
-10(4) <= Node.val <= 10(4)
思路
以前序遍历为例,遍历方式如下:
-
确定递归函数的参数和返回值
参数传入两个二叉树的根节点,返回值就是合并后二叉树的根节点 -
确定终止条件
if(t1 == NULL) return t2;// 如果 t1 为空,合并后是 t2 if(t2 == NULL) return t1;// 如果 t2 为空,合并后是 t1
-
确定单层递归的逻辑
重复利用 t1,t1是合并后树的根节点单层递归中,把两棵树的元素加到一起
t1->val += t2->val;
t1 的左子树是:合并 t1 左子树,t2 左子树之后的左子树
t1 的右子树是:合并 t1 右子树,t2 右子树之后的右子树
最终 t1 就是合并之后的根节点
t1->left = mergeTrees(t1->left, t2->left); t1->right = mergeTrees(t1->right, t2->right); return t1;
代码实现
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(root1 == NULL)return root2;
if(root2 == NULL)return root1;
root1->val += root2->val;
root1->left = mergeTrees(root1->left, root2->left);
root1->right = mergeTrees(root1->right, root2->right);
return root1;
}
};
700.二叉搜索树中的搜索
题目
给定二叉搜索树(BST)的根节点 root
和一个整数值 val
。
你需要在 BST 中找到节点值等于 val
的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null
。
示例 1:
输入:root = [4,2,7,1,3], val = 2
输出:[2,1,3]
提示:
-
数中节点数在
[1, 5000]
范围内 -
1 <= Node.val <= 10(7)
-
root
是二叉搜索树 -
1 <= val <= 10(7)
思路
递归法
- 确定递归函数的参数和返回值
参数传入的是根节点和要搜索的数值,返回这个搜索数值所在的节点
-
确定终止条件
如果 root 为空,或者找到数值,返回 root -
确定单层递归逻辑
如果 root-> val > val,搜索左子树,右子树同理但要定义一个 result 去接住指针
迭代法
代码实现
递归法
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root == NULL || root->val == val) return root;
TreeNode* result = NULL;
if(val < root->val) result = searchBST(root->left, val);
if(val > root->val) result = searchBST(root->right, val);
return result;
}
};
迭代法
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
while(root != NULL){
if(val < root->val)root = root->left;
else if(val > root->val) root = root->right;
else return root;
}
return NULL;
}
};
98.验证二叉搜索树
题目
给你一个二叉树的根节点 root
,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
-
节点的左子树只包含 小于 当前节点的数。
-
节点的右子树只包含 大于 当前节点的数。
-
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:root = [2,1,3]
输出:true
思路
中序遍历下,输出的二叉搜索树节点的数值是有序序列
验证二叉搜索树,就相当于变成了判断一个序列是不是递增的
递归法
递归中序遍历将二叉搜索树转变成一个数组,代码如下:
vector<int> vec;
void traversal (TreeNode* root)
if(root == NULL) return;
traversal(root->left);
vec.push_back(root->val);// 将二叉搜索树转换为有序数组
traversal(root->right);
}
比较一下这个数组是否是有序的,注意二叉搜索树中不能有重复元素
traversal(root);
for (int i = 1; i < vec.size(); ++i{
// 注意要小于等于,搜索树里不能有相同元素
if (vec[i] <= vec[i - 1]) return false;
}
return true;
陷阱 :
- 不能单纯地比较左节点小于中间节点,右节点大于中间节点
-
要比较的是:左子树所有节点小于中间节点,右子树所有节点大于中间节点
-
如图节点 10 大于左节点 5,小于右节点 15,但右子树里出现了 6 就不符合
-
- 样例中最小节点可能是 int 的最小值,因为不能等于,所以使用最小的 int 来比较也不行。此时可以初始化比较元素为
longlong
的最小值
递归三部曲 :
-
确定递归函数、返回值以及参数
-
定义一个
longlong
的全局变量,用来比较遍历的节点是否有序 -
函数返回值为 bool 类型,因为只有寻找某一条边(或一个节点)的时候,递归函数会有 bool 类型的返回值,代码如下
-
long long maxVal = LONG_MIN; bool isValidBST(TreeNode* root);
-
-
确定终止条件
-
二叉搜索树可以为空
if(root == NULL) return false;
-
-
确定单层递归的逻辑
-
中序遍历,一直更新 maxVal,一旦发现 maxVal >= root->val,就返回 false,注意元素相同时候也要返回 false,代码如下:
-
bool left = isValidBST(root->left); // 左 // 中序遍历,验证遍历的元素是不是从小到大 if(maxVal < root->val) maxVal = root->val; // 中 else return false; bool right = isValidBST(root->right); // 右 return left && right;
-
代码实现
这里防止了数据中右 longlong 的最小值,所以直接初始化最左边节点的数值来比较
class Solution {
public:
TreeNode* pre = NULL;
bool isValidBST(TreeNode* root) {
if(root == NULL) return true;
bool left = isValidBST(root->left);
if(pre != NULL && pre->val >= root->val)return false;
pre = root;
bool right = isValidBST(root->right);
return left && right;
}
};