一、题目打卡
1.1 最大二叉树
题目链接:. - 力扣(LeetCode)
class Solution {
private:
// 这个返回的是索引,这里创建的方式是左开右闭
int get_max(vector<int> & nums, int i, int j){
int res = i;
int flag = nums[res];
for(;i <= j;i++){
if(nums[i] > flag){
flag = nums[i];
res = i;
}
}
return res;
}
TreeNode* recur(vector<int> &nums, int i, int j){
if(i > j) return nullptr;
int res = get_max(nums,i,j);
TreeNode* node = new TreeNode(nums[res]);
node->left = recur(nums,i,res-1);
node->right = recur(nums,res + 1,j);
return node;
}
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
int len = nums.size();
return recur(nums, 0, len - 1);
}
};
递归的思想,使用双指针不断分割整个数组,由于我使用的是左闭右闭区间,因而结束的条件是右指针小于左指针,而对于每一个区间,构造的递归的子问题是:找到这个区间中的最大值所对应的索引(指针),并以这个节点构造树的节点,接着进入递归,直到区间为空。
这里需要注意的是由于我使用的是闭区间,因而在自己构造的函数 get_max 中,注意 for 循环的结束条件。
1.2 合并二叉树
题目链接:. - 力扣(LeetCode)
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
// 分三种情况进行处理:
// if(!root1 && !root2) return nullptr;
// if(!root1 && root2) return root2;
// if(root1 && !root2) return root1;
if(!root1) return root2;
if(!root2) return root1;
if(root1 && root2) root1->val = root1->val + root2->val;
root1->left = mergeTrees(root1->left,root2->left);
root1->right = mergeTrees(root1->right,root2->right);
return root1;
}
};
题目本身思路比较好理解,然后就是注意终止的条件不要写错,我一开始写错忘了考虑在递归过程中两个 root 都为空的情况,这样就会导致访问空指针,造成错误。
1.3 二叉搜索树中的搜索
题目链接:. - 力扣(LeetCode)
首先复习一下二叉搜索树(BST):
-
有序性:每个节点都包含一个键值,并且树中的每个节点的键值都大于其左子树中的任意节点的键值,同时小于其右子树中的任意节点的键值。
-
唯一性:BST中不存在重复的键值,每个键值都是唯一的。
-
左右子树:每个节点最多有两个子节点,分别称为左子节点和右子节点。
-
了解的二叉搜索树的性质了以后,这个题目不算很难:
-
递归:
-
class Solution { public: TreeNode* searchBST(TreeNode* root, int val) { if(!root) return nullptr; if(root->val == val) return root; TreeNode* res; if(val < root->val) res = searchBST(root->left,val); else res = searchBST(root->right,val); return res; } };
迭代:
-
class Solution { public: TreeNode* searchBST(TreeNode* root, int val) { TreeNode* cur = root; while(cur){ if(val == cur->val) return cur; if(val < cur->val) cur = cur->left; else cur = cur->right; } return nullptr; } };
1.4 验证二叉搜索树
题目链接:. - 力扣(LeetCode)
class Solution {
private:
bool checkLeftSons(TreeNode* root,int &val){
if(!root) return true;
return root->val < val && checkLeftSons(root->left,val) && checkLeftSons(root->right,val);
}
bool checkRightSons(TreeNode* root,int &val){
if(!root) return true;
return root->val > val && checkRightSons(root->left,val) && checkRightSons(root->right,val);
}
public:
bool isValidBST(TreeNode* root) {
if(!root) return true;
if(root->left && root->left->val >= root->val) return false;
if(root->right && root->right->val <= root->val) return false;
bool flag1 = isValidBST(root->left) && checkLeftSons(root->left,root->val);
bool flag2 = isValidBST(root->right) && checkRightSons(root->right,root->val);
return flag1 && flag2;
}
};
题目的思路比较直接,但是需要注意的是,不能仅仅只判断当前节点是否满足下一个左节点值小于当前节点值并且下一个右节点值小于当前节点值,还需要递归到后面的每一个节点进行判断。
看了答案才想起来,对于搜索树而言,一定不要忘记了它的特性:中序遍历下是一个有序数组,这样的情况,这个题目就变得简单了许多,可以直接将树序列化输出,答案的写法充分利用的这个特性,注意的是二叉搜索树是不能有重复数值的:
class Solution {
private:
vector<int> vec;
void traversal(TreeNode* root) {
if (root == NULL) return;
traversal(root->left);
vec.push_back(root->val); // 将二叉搜索树转换为有序数组
traversal(root->right);
}
public:
bool isValidBST(TreeNode* root) {
vec.clear(); // 不加这句在leetcode上也可以过,但最好加上
traversal(root);
for (int i = 1; i < vec.size(); i++) {
// 注意要小于等于,搜索树里不能有相同元素
if (vec[i] <= vec[i - 1]) return false;
}
return true;
}
};
当然也可以直接中序遍历:
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;
}
};