DAY17|二叉树Part03|LeetCode: 654.最大二叉树 、617.合并二叉树 、700.二叉搜索树中的搜索、98.验证二叉搜索树

发布于:2024-11-03 ⋅ 阅读:(130) ⋅ 点赞:(0)

目录

LeetCode:  654.最大二叉树

基本思路

C++代码

LeetCode:  617.合并二叉树 

基本思路

C++代码

LeetCode:  700.二叉搜索树中的搜索

基本思路

C++代码

LeetCode:  98.验证二叉搜索树

中序遍历+判断递增

基本思路

C++代码

递归法

C++代码


LeetCode:  654.最大二叉树

力扣代码链接

文字讲解:LeetCode:  654.最大二叉树

视频讲解:又是构造二叉树,又有很多坑!

基本思路

        需要明确的是构造树一般采用的是前序遍历因为先构造中间节点,然后递归构造左子树和右子树。

  • 确定递归函数的参数和返回值

        参数:需要传入给定的数组

        返回值:返回该数组构造的二叉树的头结点,返回类型是指向节点的指针。

TreeNode* constructMaximumBinaryTree(vector<int>& nums)
  • 确定终止条件

        我们只需要定义一个新数组,用来记录分割后的左(右)子数组,由于题目说了输入数组的大小大于等于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;
if (maxValueIndex > 0) {
    vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
    node->left = constructMaximumBinaryTree(newVec);
}
if (maxValueIndex < (nums.size() - 1)) {
    vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
    node->right = constructMaximumBinaryTree(newVec);
}

C++代码

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        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;
            }
        }
        node->val = maxValue;
        // 最大值所在的下标左区间 构造左子树
        if (maxValueIndex > 0) {
            vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
            node->left = constructMaximumBinaryTree(newVec);
        }
        // 最大值所在的下标右区间 构造右子树
        if (maxValueIndex < (nums.size() - 1)) {
            vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
            node->right = constructMaximumBinaryTree(newVec);
        }
        return node;
    }
};

LeetCode:  617.合并二叉树 

力扣代码链接

文字讲解:LeetCode:  617.合并二叉树 

视频讲解:一起操作两个二叉树?有点懵!

基本思路

        其实和遍历一个树逻辑是一样的,只不过传入两个树的节点,同时操作。

  • 确定递归函数的参数和返回值:

        首先要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。

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左子树和t2左子树。

t1->val += t2->val;
//左右子树合并
t1->left = mergeTrees(t1->left, t2->left);
t1->right = mergeTrees(t1->right, t2->right);
return t1;

C++代码

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;
    }
};

LeetCode:  700.二叉搜索树中的搜索

力扣代码链接

文字讲解:LeetCode:  700.二叉搜索树中的搜索

视频讲解:不愧是搜索树,这次搜索有方向了!

基本思路

        之前遇到的都是普通二叉树,而对于搜索树其实是一个有序树,其具有一个特性:根节点的值比左孩子小,而比右孩子大。并且子树也符合这种特性。

确定递归函数的参数和返回值

参数:传入搜索树,和要搜索的值(int类型)

返回值:我们要找到待搜索的树然后返回其结点即可

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;

C++代码

class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        if (root == NULL || root->val == val) return root;
        TreeNode* result = NULL;
        if (root->val > val) result = searchBST(root->left, val);
        if (root->val < val) result = searchBST(root->right, val);
        return result;
    }
};

LeetCode:  98.验证二叉搜索树

力扣代码链接

文字讲解:LeetCode:  98.验证二叉搜索树

视频讲解:你对二叉搜索树了解的还不够!

中序遍历+判断递增

基本思路

        如上一题提到的,搜索树的左右节点的值小于根节点,且子树也具有这个特性。那么仔细想想,中序遍历下,输出的二叉搜索树节点的数值其实是一个有序序列。有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。

C++代码

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;
    }
};

注意:这一题存在两个思维陷阱。

  • 陷阱1

        不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了。因为必须要保证左子树所有节点小于中间节点,右子树所有节点大于中间节点。如下图所示:节点10大于左节点5,小于右节点15,但右子树里出现了一个6 这就不符合了!

  • 陷阱2

        样例中的最小结点,有可能是int的最小值。如果这样的话我们可以初始化比较元素为longlong的最小值。(但如果后台数据中有int最小值测试用例该怎么办呢?这时建议避免初始化最小值,直接取最左边的数值来进行比较)

递归法

  • 确定递归函数的返回值和参数

        参数:要定义一个longlong的全局变量,用来比较遍历的节点是否有序,因为后台测试数据中有int最小值,所以定义为longlong的类型,初始化为longlong最小值。

        返回值:我们在寻找一个不符合条件的节点,如果没有找到这个节点就遍历了整个树,如果找到不符合的节点了,立刻返回,因此为bool类型。

long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
bool isValidBST(TreeNode* root)
  • 确定终止条件

        需要明确的是如果是空节点,也可以是搜索树,因此当节点为空时,则返回true

if (root == NULL) return true;
  • 确定单层递归的逻辑

        采用中序遍历,一直更新最大值,一旦发现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;

C++代码

class Solution {
public:
    long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
    bool isValidBST(TreeNode* root) {
        if (root == NULL) 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;
    }
};