【二叉树算法题记录】二叉搜索树题目汇总

700. 二叉搜索树中的搜索

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

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

题目分析

什么是二叉搜索树?

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉搜索树。

递归法

  1. 递归传入参数以及返回值
    TreeNode* searchBST(TreeNode* root, int val)
  2. 递归终止条件:有两种情况,1)当我们遍历到叶子节点之后的空节点,说明树中没有这个节点;2)当我们遍历到val匹配的节点,即找到该节点;当遇到以上两种情况时,我们就该返回结果了。if (root == NULL || root->val == val) return root;
  3. 单层递归逻辑:如果目标val小于当前节点的val,则说明它在左子树中;如果目标val大于当前节点的val,则说明它在右子树中。

整体cpp代码如下:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     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* searchBST(TreeNode* root, int val) {
        // 递归法
        // 递归终止条件:如果当前节点为空或者当前节点就是我们想找的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;
        }
};

迭代法

对于一般的二叉树,递归中存在着回溯的过程,即如果我们走一个方向走到头了,要返回到上层走另一个方向。

但是对于二叉搜索树,它的节点是有序排好的,所以不需要回溯,通过和根节点判断就能确定搜索的方向。

整体cpp代码如下:

class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        // 迭代法
        while(root!=NULL){
            if(val < root->val) root = root->left;  // 当前节点数值大于目标val,目标节点只能存在于左子树
            else if(val >root->val) root = root->right; // 当前节点数值小于目标val,目标节点只能存在于右子树
            else return root;   // 当前节点数值等于目标val,找到目标节点,直接返回
        }
        return root;
        }
};

98. 验证二叉搜索树

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

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

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

题目分析

演化为判断数组是否有序

基于二叉搜索树的本质,它的中序遍历是有序的,即从小到大排列,所以直观方法是得到该二叉树的中序遍历数组,然后问题转换为判断数组是否有序

所以我们根据上述分析可以写出以下代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     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:
    void traversal(TreeNode* cur, vector<int>& vec){
        if(cur==NULL) return;
        // 左
        traversal(cur->left, vec);
        // 中
        vec.push_back(cur->val);
        // 右
        traversal(cur->right, vec);
    }
    bool isValidBST(TreeNode* root) {   // 二叉搜索树的中序遍历结果是有序的
        if(root==NULL) return true;

        vector<int> vec;
        traversal(root, vec);

        for(int i = 0; i < vec.size(); i++){
            if(i>0 && vec[i] <= vec[i-1])
                return false;
        }
        return true;
    }
};

递归的同时判断是否有序

上面是将递归过程转变为数组,最后再判断,那么如何同时在递归过程中进行判断呢?

有两点容易混淆:

  • 对于当前递归节点TreeNode* cur来说,我们不是单纯比较它的左孩子和右孩子的值,而是左子树和右子树,即是说cur要比它左子树的任意一个节点大,比右子树的任意一个节点小。
  • 这题规定 − 2 31 < = N o d e . v a l < = 2 31 − 1 -2^{31} <= Node.val <= 2^{31} - 1 231<=Node.val<=2311,也就是说节点的值可能为int(4个byte)的最小值,我们不能使用最小的int来比较,因此可以初始化比较元素为long long(8个byte)类型。

以上两点明确后,我们可以开始设计递归函数:

  • 确定递归参数和返回值
    首先定义一个long long类型的全局变量,用来比较遍历的节点是否有序,因为Node.val的值可能是int最小值,我们要设置一个比Node.val都要小的值,所以就初始化为long long最小值。
    因为我们要寻找某一条边,所以递归函数要返回bool类型。
long long maxVal = LONG_MIN;
bool isValidBST(TreeNode* cur)
  • 确定递归终止条件
if (root == NULL) return true;
  • 单层递归逻辑
    左中右的处理顺序。
    对于当前节点cur来说,我们要与maxVal来进行比较,判断当前遍历到的节点是不是有序的,如果不是,就要返回false,如果是,则要更新maxVal
bool left = isValidBST(cur->left);         // 左

// 中序遍历,验证遍历的元素是不是从小到大
if (maxVal < cur->val) maxVal = cur->val; // 中
else return false;

bool right = isValidBST(cur->right);       // 右
return left && right;

整体cpp代码如下:

class Solution {
public:
    long long maxValue = LONG_MIN;  // 定义全局变量进行递归时的判断
    bool isValidBST(TreeNode* root) {
        // 递归终止条件
        if(root==NULL) return true;
        
        // 单层递归逻辑
        bool left = isValidBST(root->left);  // 左
        if(maxValue < root->val)  // 中
            maxValue = root->val;   // 更新maxValue的值
        else return false;
        bool right = isValidBST(root->right);    // 右

        return left && right;   // 总结左右两条边的值并返回
    }
};
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值