654 最大二叉树
题目
https://leetcode.cn/problems/maximum-binary-tree/description/
我的想法
中序遍历递归,找到最大值然后作为根节点
题目分析
凡是构造二叉树的题目都用前序遍历 (中左右)
为先构造中间节点,然后递归构造左子树和右子树。
确定递归函数的参数和返回值
参数传入的是存放元素的数组,返回该数组构造的二叉树的头结点,返回类型是指向节点的指针。
1.确定终止条件
题目中说了输入的数组大小一定是大于等于1的,所以我们不用考虑小于1的情况,那么当递归遍历的时候,如果传入的数组大小为1,说明遍历到了叶子节点了。
那么应该定义一个新的节点,并把这个数组的数值赋给新的节点,然后返回这个节点。 这表示一个数组大小是1的时候,构造了一个新的节点,并返回。
TreeNode* node = new TreeNode(0);
if (nums.size() == 1) {
node->val = nums[0];
return node;
}
确定单层递归逻辑
这里有三步工作
先要找到数组中最大的值和对应的下标, 最大的值构造根节点,下标用来下一步分割数组。
最大值所在的下标左区间 构造左子树
这里要判断maxValueIndex > 0,因为要保证左区间至少有一个数值。
最大值所在的下标右区间 构造右子树
判断maxValueIndex < (nums.size() - 1),确保右区间至少有一个数值。
acm模式代码
cpp
#include <iostream>
#include <vector>
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x):val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode* left, TreeNode* right):val(x), left(left), right(right) {}
};
class Solution {
public:
TreeNode* constrcuctMaxinumBinaryTree(std::vector<int>& num) {
TreeNode* node = new TreeNode(0);
if (num.size() == 1) {
node->val = num[0];
return node;
}
int maxvalue = 0;
int maxvalueIndex = 0;
for (int i = 0; i < num.size(); i++) {
if (num[i] > maxvalue) {
maxvalue = num[i];
maxvalueIndex = i;
}
}
node->val = maxvalue;
if(maxvalueIndex > 0) {
std::vector<int> newVec(num.begin(), num.begin() + maxvalueIndex);
node->left = constrcuctMaxinumBinaryTree(newVec);
}
if (maxvalueIndex < num.size()-1) {
std::vector<int> newVec(num.begin() + maxvalueIndex + 1, num.end());
node->right = constrcuctMaxinumBinaryTree(newVec);
}
return node;
}
};
void printTree(TreeNode* node) {
if (node != nullptr) {
printTree(node->left);
std::cout << node->val << " ";
printTree(node->right);
}
}
int main() {
// 创建一个整数向量
std::vector<int> nums = {3, 2, 1, 6, 0, 5};
// 创建Solution实例并构建最大二叉树
Solution solution;
TreeNode* root = solution.constrcuctMaxinumBinaryTree(nums);
// 打印构建的二叉树
std::cout << "The constructed maximum binary tree (inorder): ";
printTree(root);
std::cout << std::endl;
// 注意:这里没有删除TreeNode的实例,实际应用中应考虑内存管理
return 0;
}
617 合并二叉树
题目描述
https://leetcode.cn/problems/merge-two-binary-trees/description/
我的想法
还是构造新的二叉树,选择前序遍历
题目分析
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
我们来按照递归三部曲来解决:
- 确定递归函数的参数和返回值:
首先要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。
代码如下:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
- 确定终止条件:
因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。
反过来如果t2 == NULL,那么两个数合并就是t1(如果t1也为NULL也无所谓,合并之后就是NULL)。
代码如下:
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;
acm完整代码
cpp
#include <iostream>
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x):val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode* left, TreeNode* right):val(x), left(left), right(right) {}
};
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if (root1 == nullptr) return root2;
if (root2 == nullptr) return root1;
TreeNode* root = new TreeNode(0);
root->val = root1->val + root2->val;
root->left = mergeTrees(root1->left, root2->left);
root->right = mergeTrees(root1->right, root2->right);
return root;
}
};
void printTree(TreeNode* node) {
if (node != nullptr) {
std::cout << node->val << " ";
printTree(node->left);
printTree(node->right);
}
}
int main() {
// 创建两个树的根节点
TreeNode* root1 = new TreeNode(1);
root1->left = new TreeNode(3);
root1->right = new TreeNode(2);
root1->left->left = new TreeNode(5);
TreeNode* root2 = new TreeNode(2);
root2->left = new TreeNode(1);
root2->right = new TreeNode(3);
root2->left->right = new TreeNode(4);
root2->right->right = new TreeNode(7);
// 合并两棵树
Solution solution;
TreeNode* mergedTree = solution.mergeTrees(root1, root2);
// 打印合并后的树
std::cout << "The merged tree (inorder): ";
printTree(mergedTree);
std::cout << std::endl;
// 注意:这里没有删除TreeNode的实例,实际应用中应考虑内存管理
delete root1;
delete root2;
delete mergedTree;
return 0;
}
700二叉搜索树中的搜索
题目描述
https://leetcode.cn/problems/search-in-a-binary-search-tree/description/
我的想法
直接用前序遍历,遍历到值相等的节点就作为根节点返回
题目分析
二叉搜索树是一个有序树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉搜索树
这就决定了,二叉搜索树,递归遍历和迭代遍历和普通二叉树都不一样。
本题,其实就是在二叉搜索树中搜索一个节点。那么我们来看看应该如何遍历。
递归法
- 确定递归函数的参数和返回值
递归函数的参数传入的就是根节点和要搜索的数值,返回的就是以这个搜索数值所在的节点。
代码如下:
TreeNode* searchBST(TreeNode* root, int val)
-
确定终止条件
如果root为空,或者找到这个数值了,就返回root节点。if (root == NULL || root->val == val) return root;
-
确定单层递归的逻辑
看看二叉搜索树的单层递归逻辑有何不同。
因为二叉搜索树的节点是有序的,所以可以有方向的去搜索。
如果root->val > val,搜索左子树,如果root->val < val,就搜索右子树,最后如果都没有搜索到,就返回NULL。
代码如下:
TreeNode* result = NULL;
if (root->val > val) result = searchBST(root->left, val);
if (root->val < val) result = searchBST(root->right, val);
return result;
acm模式代码
cpp
class Solution{
public:
TreeNode* searchBST(TreeNode* root, int val) {
if (root == nullptr) return nullptr;
if (root->val == val) return root;
TreeNode* leftSearch = searchBST(root->left, val);
if (leftSearch != nullptr) return leftSearch;
return searchBST(root->right, val);
}
void printTree(TreeNode* root) {
if (root == nullptr) return;
std::cout << root->val << " ";
printTree(root->left);
printTree(root->right);
}
};
int main() {
TreeNode* node = new TreeNode(3);
node->left = new TreeNode(2);
node->right = new TreeNode(3);
node->left->left = new TreeNode(4);
node->left->right = new TreeNode(5);
Solution* sol = new Solution();
TreeNode* newnode = sol->searchBST(node, 2);
sol->printTree(newnode);
// 注意:这里没有删除TreeNode的实例和Solution的实例,实际应用中应考虑内存管理
return 0;
}
98验证二叉搜索树
题目描述
https://leetcode.cn/problems/validate-binary-search-tree/description/
我的想法
采用后序遍历,比较两个儿子是否满足条件。
题目分析
二叉搜索类题目中序遍历是有序的
有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。
可以递归中序遍历将二叉搜索树转变成一个数组,代码如下:
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;
完整acm模式代码
cpp
#include <iostream>
#include <vector>
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x):val(x) ,left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode* left, TreeNode* right) {}
};
class Solution{
public:
std::vector<int> vec;
void traversal(TreeNode* root) {
if (root == nullptr) return;
traversal(root->left);
vec.push_back(root->val);
traversal(root->right);
}
bool isValidBST(TreeNode* root) {
traversal(root);
for (int i = 1; i < vec.size(); i++) {
if (vec[i] <= vec[i - 1]) return false;
}
return true;
}
};
int main() {
// Create nodes
TreeNode* n1 = new TreeNode(2);
TreeNode* n2 = new TreeNode(1);
TreeNode* n3 = new TreeNode(3);
// Construct the tree
n1->left = n2;
n1->right = n3;
// Create a solution instance
Solution solution;
// Check if the tree is a valid BST
bool result = solution.isValidBST(n1);
if (result) {
std::cout << "The tree is a valid BST." << std::endl;
} else {
std::cout << "The tree is not a valid BST." << std::endl;
}
// Clean up
delete n1;
delete n2;
delete n3;
return 0;
}