代码随想录算法训练营第二十天 | 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

本文介绍了如何构建最大二叉树、合并二叉树以及验证二叉搜索树的有效性。首先,通过递归的方式详细阐述了最大二叉树的构建过程,接着讲解了合并两个二叉树的算法,最后讨论了验证二叉搜索树的中序遍历方法。这些算法均涉及到二叉树的递归操作和前序遍历。
摘要由CSDN通过智能技术生成

654.最大二叉树

题目

给定一个不重复的整数数组 nums最大二叉树 可以用下面的算法从 nums 递归地构建:

  1. 创建一个根节点,其值为 nums 中的最大值。

  2. 递归地在最大值 左边子数组前缀上 构建左子树。

  3. 递归地在最大值 右边子数组后缀上 构建右子树。

返回 nums 构建的 最大二叉树

示例:

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:
- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5]- [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1]- 空数组,无子节点。
        - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1]- 空数组,无子节点。
            - 只有一个元素,所以子节点是一个值为 1 的节点。
    - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 []- 只有一个元素,所以子节点是一个值为 0 的节点。
        - 空数组,无子节点。

在这里插入图片描述

提示:

  • 1 <= nums.length <= 1000

  • 0 <= nums[i] <= 1000

  • nums 中的所有整数 互不相同

思路

💡凡是构造二叉树的题目,都要用前序遍历

最大二叉树的构建过程如下:

在这里插入图片描述

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

    • 参数就是传入的是存放元素的数组,返回该数组构造的二叉树的头结点,返回类型是指向节点的指针
  • 确定终止条件

    • 输入的数组大小一定是大于等于 1,所以不需要考虑小于 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;
      
    • 最大值所在的下标左区间,构造左子树。这里要判断 maxValueIndex > 0,因为要保证左区间至少有一个数值

      if(maxValueIndex > 0){
          vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
          node->left = constructMaximumBinaryTree(newVec);
      }
      
    • 最大值所在的下标右区间,构造右子树。判断 maxValueIndex < (num.size() - 1),确保右区间至少有一个数值

      if(maxValueIndex < (nums.size() - 1)){
         vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
         node->right = constructMaximumBinaryTree(newVec);
      }
      

代码实现

  • 返回类型 TreeNode* construct(vec nums)

  • 终止条件:

    • if(num.size == 1)
      • return new TreeNode(nums[0]);
  • 单层递归逻辑:

    • 中:
    • int maxValue = 0
    • int index = 0
    • for(int i = 0; i < nums.size(); i++){
      • if(nums[i]>maxValue){
        • maxValue = num[i];
        • index = i
    • node = new TreeNode(maxValue)
    • 左:
    • if(index > 0)
      • newVec(0, index); 左闭右开
      • node->left = contruct(newVec);
    • 右:
    • if(index < nums.size-1)
      • newVec(index+1, nums.size)
      • node->right = contruct(newVec);
    • return node;

优化:不要每次构造新的 vector,控制下标就好

class Solution {
private:
    TreeNode* traversal(vector<int>& nums, int left, int right){
        if(left >= right)return nullptr;

        int maxValueIndex = left;
        for(int i = left + 1; i < right; ++i){
            if(nums[i] > nums[maxValueIndex]) maxValueIndex = i;
        }
        TreeNode* root = new TreeNode(nums[maxValueIndex]);

        root->left = traversal(nums, left, maxValueIndex);
        root->right = traversal(nums, maxValueIndex + 1, right);

        return root;
    }
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traversal(nums, 0, nums.size());
    }
};

617.合并二叉树

题目

给你两棵二叉树: root1root2

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

在这里插入图片描述

提示:

  • 两棵树中的节点数目在范围 [0, 2000]

  • -10(4) <= Node.val <= 10(4)

思路

以前序遍历为例,遍历方式如下:
在这里插入图片描述

  1. 确定递归函数的参数和返回值
    参数传入两个二叉树的根节点,返回值就是合并后二叉树的根节点

  2. 确定终止条件

       if(t1 == NULL) return t2;// 如果 t1 为空,合并后是 t2
       if(t2 == NULL) return t1;// 如果 t2 为空,合并后是 t1
    
  3. 确定单层递归的逻辑
    重复利用 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;
    

代码实现

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(root1 == NULL)return root2;
        if(root2 == NULL)return root1;

        root1->val += root2->val;

        root1->left = mergeTrees(root1->left, root2->left);
        root1->right = mergeTrees(root1->right, root2->right);

        return root1;
    }
};

700.二叉搜索树中的搜索

题目

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null

示例 1:

输入:root = [4,2,7,1,3], val = 2
输出:[2,1,3]

在这里插入图片描述

提示:

  • 数中节点数在 [1, 5000] 范围内

  • 1 <= Node.val <= 10(7)

  • root 是二叉搜索树

  • 1 <= val <= 10(7)

思路

递归法

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

参数传入的是根节点和要搜索的数值,返回这个搜索数值所在的节点

  1. 确定终止条件
    如果 root 为空,或者找到数值,返回 root

  2. 确定单层递归逻辑
    如果 root-> val > val,搜索左子树,右子树同理

    但要定义一个 result 去接住指针

迭代法

在这里插入图片描述

代码实现

递归法

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

迭代法

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

98.验证二叉搜索树

题目

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。

  • 节点的右子树只包含 大于 当前节点的数。

  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:root = [2,1,3]
输出:true

在这里插入图片描述

思路

中序遍历下,输出的二叉搜索树节点的数值是有序序列

验证二叉搜索树,就相当于变成了判断一个序列是不是递增的

递归法

递归中序遍历将二叉搜索树转变成一个数组,代码如下:

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;

陷阱

  1. 不能单纯地比较左节点小于中间节点,右节点大于中间节点
    1. 要比较的是:左子树所有节点小于中间节点,右子树所有节点大于中间节点

    2. 如图节点 10 大于左节点 5,小于右节点 15,但右子树里出现了 6 就不符合

在这里插入图片描述

  1. 样例中最小节点可能是 int 的最小值,因为不能等于,所以使用最小的 int 来比较也不行。此时可以初始化比较元素为 longlong 的最小值

递归三部曲

  • 确定递归函数、返回值以及参数

    • 定义一个 longlong 的全局变量,用来比较遍历的节点是否有序

    • 函数返回值为 bool 类型,因为只有寻找某一条边(或一个节点)的时候,递归函数会有 bool 类型的返回值,代码如下

    • long long maxVal = LONG_MIN;
      bool isValidBST(TreeNode* root);
      
  • 确定终止条件

    • 二叉搜索树可以为空

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

    • 中序遍历,一直更新 maxVal,一旦发现 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;
      

代码实现

这里防止了数据中右 longlong 的最小值,所以直接初始化最左边节点的数值来比较

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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值