day19是休息日,到时候我会补一篇关于二叉树的总结。
所以今天是day20.
链接: 最大二叉树
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。
每个二叉树节点都可以认为是一棵子树的根节点,对于根节点,首先要做的当然是把想办法把自己先构造出来,然后想办法构造自己的左右子树。
所以,我们要遍历数组把找到最大值 maxVal,从而把根节点 root 做出来,然后对 maxVal 左边的数组和右边的数组进行递归构建,作为 root 的左右子树。
还是递归
class Solution {
public:
/* 主函数 */
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return build(nums, 0, nums.size() - 1);
}
/* 定义:将 nums[lo..hi] 构造成符合条件的树,返回根节点 */
TreeNode* build(vector<int>& nums, int lo, int hi) {
/* base case */
if (lo > hi) {
return nullptr;
}
/* 找到数组中的最大值和对应的索引 */
int index = -1, maxVal = INT_MIN;
for (int i = lo; i <= hi; i++) {
if (maxVal < nums[i]) {
index = i;
maxVal = nums[i];
}
}
TreeNode* root = new TreeNode(maxVal);
/* 递归调用构造左右子树 */
root->left = build(nums, lo, index - 1);
root->right = build(nums, index + 1, hi);
return root;
}
};
链接: 合并二叉树
前序遍历
前序遍历后序遍历都可以,前序最简单
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2
if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1
// 修改了t1的数值和结构
t1->val += t2->val; // 中
t1->left = mergeTrees(t1->left, t2->left); // 左
t1->right = mergeTrees(t1->right, t2->right); // 右
return t1;
}
};
链接: 二叉搜索树中的搜索
利用 BST 左小右大的特性,可以避免搜索整棵二叉树去寻找元素,从而提升效率。
使用BST,也是递归逻辑。
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int target) {
if (root == NULL) {
return NULL;
}
// 去左子树搜索
if (root->val > target) {
return searchBST(root->left, target);
}
// 去右子树搜索
if (root->val < target) {
return searchBST(root->right, target);
}
return root;
}
};
链接: 验证二叉搜索树
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左
子树
只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
还是使用递归
我做这题很容易有误区:BST 不是左小右大么,那我只要检查 root.val > root.left.val 且 root.val < root.right.val 不就行了?
这样是不对的,因为 BST 左小右大的特性是指 root.val 要比左子树的所有节点都更大,要比右子树的所有节点都小,你只检查左右两个子节点当然是不够的。
正确解法是通过使用辅助函数,增加函数参数列表,在参数中携带额外信息,将这种约束传递给子树的所有节点,这也是二叉搜索树算法的一个小技巧
class Solution {
public:
bool isValidBST(TreeNode* root) {
// 限定以root为根的子树节点必须满足max.val > root.val > min.val
return checkValidBST(root, nullptr, nullptr);
}
// 限定root节点符合min和max的限制
bool checkValidBST(TreeNode* root, TreeNode* minNode, TreeNode* maxNode) {
// base case
if (root == nullptr) return true;
// 若root.val不符合max和min的限制,说明不是合法BST
if (minNode != nullptr && root->val <= minNode->val) return false;
if (maxNode != nullptr && root->val >= maxNode->val) return false;
// 限定左子树的最大值是root.val,右子树的最小值是root.val
return checkValidBST(root->left, minNode, root)
&& checkValidBST(root->right, root, maxNode);
}
};