654.最大二叉树
思路:和前序构造二叉树一样,找到最大的值的下标,划分左右区间,然后进入迭代
要注意的就是要保证区间(循环不变量原则)
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
//是 1 是因为题目要求 1 <= nums.length <= 1000
TreeNode* node = new TreeNode(0);
if (nums.size() == 1) {
node->val = nums[0];
return node;
}
//找数组里面的最大值,然后将该点值成为根节点,然后分割重复
int maxVal = 0; //0 <= nums[i] <= 1000
int index = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > maxVal) {
maxVal = nums[i];
index = i;
}
}
// TreeNode* node = new TreeNode(0);
node->val = maxVal;
//分割左子树
if (index > 0) {
vector<int> newLeft(nums.begin(), nums.begin() + index);
node->left = constructMaximumBinaryTree(newLeft);
}
//分割右子树 都是遵循左闭右开
if (index < nums.size() - 1) {
vector<int> newRight(nums.begin() + index + 1, nums.end());
node->right = constructMaximumBinaryTree(newRight);
}
return node;
}
};
简化代码如下:
class Solution {
public:
// 在左闭右开区间[left, right),构造二叉树
TreeNode* traversal(vector<int>& nums, int left, int right) {
if (left >= right) return nullptr;
// 分割点下标:maxIndex
int maxIndex = left;
for (int i = left + 1; i < right; i++) {
if (nums[i] > nums[maxIndex]) maxIndex = i;
}
TreeNode* node = new TreeNode(nums[maxIndex]);
// 左闭右开:[left, maxValueIndex)
node->left = traversal(nums, left, maxIndex);
// 左闭右开:[left, maxValueIndex)
node->right = traversal(nums, maxIndex + 1, right);
return node;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return traversal(nums, 0, nums.size());
}
};
注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,这样可以节约时间和空间上的开销。
一些同学也会疑惑,什么时候递归函数前面加if,什么时候不加if,这个问题我在最后也给出了解释。
其实就是不同代码风格的实现,一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。
617.合并二叉树
思路递归三件套
1、确定递归函数的参数和返回值:
首先要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。
2、确定终止条件:
因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。
反过来如果t2 == NULL,那么两个数合并就是t1(如果t1也为NULL也无所谓,合并之后就是NULL)。
3、确定单层递归的逻辑:
单层递归的逻辑就比较好写了,这里我们重复利用一下t1这个树,t1就是合并之后树的根节点(就是修改了原来树的结构)。
接下来t1 的左子树是:合并 t1左子树 t2左子树之后的左子树。
t1 的右子树:是 合并 t1右子树 t2右子树之后的右子树。
最终t1就是合并之后的根节点。
当然也可以新建一颗树来实现操作两个二叉树
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if (root1 == nullptr) return root2;
if (root2 == nullptr) return root1;
TreeNode* node = new TreeNode(0);
node->val = root1->val + root2->val;
node->left = mergeTrees(root1->left, root2->left);
node->right = mergeTrees(root1->right, root2->right);
return node;
}
};
总结
本题可以使用前序后序中序,但是前序是最好理解的,思路和我们构造二叉树的思维是一样的。
700.二叉搜索树中的搜索
思路: 搞明白二叉搜索树的概念:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉搜索树
明白了概念以后,本题就很容易解决了
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if (root == nullptr || val == root->val) return root;
if (val < root->val) return searchBST(root->left, val);
if (val > root->val) return searchBST(root->right, val);
return nullptr;
}
};
迭代法
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
while (root != nullptr) {
if (val > root->val) root = root->right;
else if (val < root->val) root = root->left;
else return root;
}
return nullptr;
}
};
总结:二叉搜索树(BST)的概念决定了搜索的方向,所以本题很简单,就是在树内找节点元素,迭代法递归法都很简单。
98.验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
思路: (直白思路)
首先遍历整个二叉树(按照中序遍历),得到一个数组,根据二叉搜索树的概念,那么得到的这个数组一定是个升序的数组,比较数组的元素和前一个元素,当有不满足的情况,返回false,其他情况返回true;
class Solution {
public:
vector<int> ans;
bool isValidBST(TreeNode* root) {
if (root == nullptr) return true;
isValidBST(root->left);
ans.push_back(root->val);
isValidBST(root->right);
for (int i = 1; i < ans.size(); i++) {
if (ans[i] <= ans[i - 1]) return false;
}
return true;
}
};
思路2:因为构建数组会导致时间空间增加,所以可以通过比较节点是否有序的方法来判断
class Solution {
public:
long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值 -2^31 <= Node.val <= 2^31 - 1
bool isValidBST(TreeNode* root) {
if (root == nullptr) return true;
bool left = isValidBST(root->left); // 左
if (maxVal < root->val) {
maxVal = root->val;
} else return false;
bool right = isValidBST(root->right); // 右
return left && right;
}
};
class Solution {
public:
TreeNode* pre = nullptr; // 记录前一个节点
bool isValidBST(TreeNode* root) {
if (root == nullptr) return true;
bool left = isValidBST(root->left);
if (pre != nullptr && pre->val >= root->val) {
return false;
}
pre = root; // 记录前一个节点
bool right = isValidBST(root->right);
return left && right; // 返回的时候都为true才是true
}
};
总结:这道题直接做也行,但是会消耗空间和时间,可以考虑新建一个前节点,然后二叉搜索树的概念,用中序遍历的过程中比较大小,比较后移动。
文章介绍了如何使用递归和迭代方法构造最大二叉树,合并二叉树以及在二叉搜索树中进行搜索。关键在于理解二叉树的性质,如最大值作为根节点、左子树小于根节点、右子树大于根节点等。对于验证二叉搜索树的有效性,可以通过中序遍历并比较节点值来实现。

被折叠的 条评论
为什么被折叠?



