Leetcode—二叉搜索树

概念

二叉搜索树又称为二叉排序树,即根节点的左子树都比根节点小,根节点右子树都比根节点大。

第700题 二叉搜索树中的搜索

在这里插入图片描述

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

第98题 验证二叉搜索树

在这里插入图片描述在这里插入图片描述

class Solution {
public:
    void midorder(TreeNode* root,vector<int>& arry)
    {
        if(root==nullptr)
            return ;
        midorder(root->left,arry);
        arry.push_back(root->val);
        midorder(root->right,arry);
    }
    bool isValidBST(TreeNode* root) {
        //二叉搜索树的中序遍历是一个升序数组,可以利用这个升序数组进行判断
        vector<int> arry;
        midorder(root,arry);
        //判断数组是否升序
        for(int i = 0;i<arry.size()-1;i++)
        {
            if(arry[i]>=arry[i+1])
                return false;
        }
        return true;
    }
};

递归法

class Solution {
public:
    long long minval = LONG_MIN;
    //递归法
    bool isValidBST(TreeNode* root) {
    //中序遍历
    if(root==nullptr)
        return true;
    //算法思想同数组操作,即比较整个遍历过程中,元素是不是升序的
    bool left = isValidBST(root->left);
    if(root->val > minval) minval = root->val;
    else
        return false;
    bool right = isValidBST(root->right);

    return left && right;
    }
};

第530题 二叉搜索树的最小绝对值差

在这里插入图片描述
在这里插入图片描述
**解题思路:**直接对二叉搜索树进行中序遍历,得到的是一个升序数组,然后就可直接求最小差值。

class Solution {
public:
    void midTravel(TreeNode* root,vector<int> &nums)
    {
        if(root == nullptr) return;
        midTravel(root->left,nums);
        nums.push_back(root->val);
        midTravel(root->right,nums);
    }
    int getMinimumDifference(TreeNode* root) {
        //中序遍历得到的是升序数组,即可求得最小差值
        int min_val = INT_MAX;
        vector<int> nums;
        midTravel(root,nums);
        for(int i = 0;i<nums.size()-1;i++)
        {
            min_val = (min_val<(nums[i+1]-nums[i]))?min_val:(nums[i+1]-nums[i]);
        }
        return min_val;
    }
};

第501题 二叉搜索树中的众数

在这里插入图片描述
在这里插入图片描述
解题思路:采用中序遍历,一边遍历一边记录当前节点出现的频率,若是最大频率,就存入结果中,若出现了更大的频率数字,则清空结果集,重新放入数据。

class Solution {
public:
    int count = 0;//用于统计频率的
    int maxCount = 0;//最大频率
    TreeNode* pre = NULL;
    vector<int> res;
    void midTravel(TreeNode* root)
    {
        if (root == nullptr) return;
        midTravel(root->left);
        //若当前是第一个节点
        if(pre == NULL) count = 1;
        else if (pre->val == root->val) count++;  //当前节点与前一个结点相同
        else
            count = 1;//不是第一个节点也与前面也不同。重新计数
        pre = root;
        if(count == maxCount) res.push_back(root->val);//若当前数字出现的频率等于最大频率,放进res中
        if(count>maxCount)
        {
            //更新res
            maxCount = count;
            res.clear();
            res.push_back(root->val);
        }
        midTravel(root->right);
    }
    vector<int> findMode(TreeNode* root) {
        //中序遍历
        midTravel(root);
        return res;
    }
};

第236题 二叉树的最近公共祖先

在这里插入图片描述
在这里插入图片描述
解题思路:采用的是先序遍历,首先明确什么时候递归结束?即当前结点是要寻找的节点,或者空的时候,递归结束;最近公共祖先的寻找方法是递归加回溯,设置两个指针left和right,若left和right都不为空,说明在当前结点找到了符合标准的孩子,当前节点root就是最近公共祖先,因为回溯是自下而上,所以一旦两个都找到了,必然是最近祖先。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        //递归返回条件
        if (root == NULL || root == p || root == q)
            return root;
        TreeNode* left = lowestCommonAncestor(root->left,p,q);//记录左子树是否包含要找的节点,有就返回当前左子树的根节点
        TreeNode* right = lowestCommonAncestor(root->right,p,q);//t同理

        if(left != NULL && right != NULL)//当左右节点都不空,说明当前节点的左右子树里包含要找的节点,该根节点就是最近公共祖先
            return root;
        else if(left != NULL)
            return left;
        else if (right != NULL)
            return right;
        
        return NULL;
    }
};

第236 二叉搜索树的最近公共祖先

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
解题思路:整体思想与上述题目类似,但是注意利用二叉搜索树的性质,即当前根节点的值在p与q之间,并且二叉搜索树没有重复值,即可判断当前节点为p和q的最近公共祖先,若当前节点比最小值还要小,往左子树找,否则就往右子树找。(注意本题中所给的p和q不一定p值小于q值);

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        //递归结束条件
        int small = min(p->val,q->val);
        int big = max(p->val,q->val);
        if(root->val >= small && root->val<=big)
            return root;
        
        if (root->val > big)
            return lowestCommonAncestor(root->left,p,q);
        else if(root->val < small)
            return lowestCommonAncestor(root->right,p,q);
        else 
            return root;
    }
};

第701题 二叉搜索树中的插入操作

在这里插入图片描述
在这里插入图片描述
解题思路:插入时考虑三种情况。a)若当前树为空,直接进行插入;b)若当前树不为空,从根节点开始查找待插入节点的位置,当val值大于根节点值,即要把他插入到右子树上,否则就往左子树上插入;c)若根节点的左子树或右子树为空是,直接插上去就行,若待插入位置有节点是,递归进去,找有空结点的位置。

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == nullptr)
        {
            TreeNode* node = new TreeNode(val);
            root = node;
        }
        else if(root->val < val)
        {
            if (root->right == nullptr)
            {
                TreeNode* node = new TreeNode(val);
                root->right = node;
            }
            else
                root->right = insertIntoBST(root->right,val);
        }
        else
        {
            if (root->left == nullptr)
            {
                TreeNode* node = new TreeNode(val);
                root->left = node;
            }
            else
                root->left = insertIntoBST(root->left,val);
        }
        return root;
    }
};

第450题 删除二叉搜索树中的节点

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解题思路:这里采用的是答案给的第二种删除方法。此题主要考察的是对搜索二叉树的细节操作,首先考虑如何递归,很简单,当前节点小于给定节点值,向右进行递归,当前节点大于给定节点,向左递归,当找到要删除节点时,这是题目重点考察地方!!!若要删除的节点没有左右孩子,直接删掉它就行;若要删除的节点只有一个子树,那么我们要先重新确定这个树的根节点,即他的子树的根节点,然后再删除节点;最复杂的一种情况,要删除的节点左右子树都存在,采用的方法是选这个节点的左孩子作为新的根节点,然后把原来树的右子树插入到原来树的左子树上最大值的右子树上,有点绕,上图:
在这里插入图片描述

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        //树为空,直接返回
        if(root == nullptr)
            return root;
        //若当前结点的子结点是要删除的结点
        if(root->val == key)
        {
            TreeNode* temp = root;//保存一下要删除的结点
            if (root->left == nullptr && root->right == nullptr)//没有子树
                //直接删除
                root = nullptr;
            else if(root->left && root->right == nullptr)//当左子树不为空,右子树为空,左子树成为新的根
                root = root->left;
            else if(root->right && root->left == nullptr)//当右子树不为空,左子树为空,右子树成为新的根
                root = root->right;
            else //当左右子树都在,删除根节点之前要指定新的根节点,然后将右子树挂在左子树最大结点的右指针上
            {
                //更新根节点
                root = temp->left;
                //找左子树最大值(必定是叶子节点)
                TreeNode* p = root;
                //找最大值就一直找右子树就行
                while(p->right!=nullptr)
                    p = p->right;
                //找到之后将原来的右子树挂在p的右指针上
                p->right = temp->right;
            }
            delete(temp);
        }

        //若当前结点不是要删除的结点,判断递归应该进左子树还是右子树
        else if(root->val < key)
            root->right = deleteNode(root->right,key);
        else
            root->left = deleteNode(root->left,key);
        
        return root;
    }
};

第669题 修剪二叉搜索树

在这里插入图片描述在这里插入图片描述
解题思路:与上一题思想一致

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        //整体跟前一题是一样的
        if(root == nullptr)
            return root;
        //若遇见了要删除的节点
        if(root->val < low || root->val > high)
        {
            TreeNode* temp = root;
            //按照要删除节点的不同类型进行不同的操作
            if(root->left == nullptr && root->right == nullptr)
                return nullptr;
            else if(root->left == nullptr && root->right != nullptr)
                root = temp->right;
            else if(root->left != nullptr && root->right == nullptr)
                root = temp->left;
            else
                {
                    root = temp->left;
                    TreeNode* p = temp;
                    while(p->right!=nullptr)
                        p = p->right;
                    p->right = temp->right;

                }
            delete(temp);
        }
        root->left = trimBST(root->left, low, high);
        root->right = trimBST(root->right, low, high);

        return root;
    }
};

第108题 将有序数组转换为二叉搜索树

在这里插入图片描述
在这里插入图片描述
解题思路:题目的重点在于构建一个高度平衡的二叉搜索树,因此在插入的过程中要注意如何选取下一个待插入点,才能保证构建完的二叉树是一个平衡的二叉树,这里采用的方法类似于二分查找的方法,即将数组的中间节点作为树的根节点,然后以中间节点为界,将数组划分为两个子数组,通过递归,将子数组中的中间节点作为子树的根节点插入,以此类推,构建完的二叉搜索树自然而然为一个平衡树。

class Solution {
public:
    void insertNode(TreeNode*& root,vector<int>& nums,int low,int high)
    {
        if (low<=high)
        {
            int middle = (low+high)/2;//将数组中间节点作为根节点
            int key = nums[middle];
            if(root == nullptr)
                root = new TreeNode(key);
            //将数组进行划分,分别开始构建左右子树
            insertNode(root->left,nums,low,middle-1);
            insertNode(root->right,nums,middle+1,high);
        }
        else
            root = nullptr;
    }
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        //每次取数组的中间节点作为根节点
        //将数据的插入写在一个新函数中
        int low = 0,high = size(nums) - 1;
        TreeNode* root = nullptr;
        insertNode(root,nums,low,high);
        return root;
    }
};

第538题 把二叉搜索树转换为累加树

在这里插入图片描述在这里插入图片描述
解题思路:观察这颗二叉累加树是如何构造的,我们从累加树中最小值开始看,发现原来二叉搜索树中最大值还保留它原来的值,因为没有比他再大的数了;然后再看它的父节点,根据二叉搜索树性质,他的父节点比它小,所以再累加树中变成了8+7;好,接下来我们看节点5,按照二叉搜索树性质,它在左子树上,那么根节点和根节点的右子树上的数都比它大,所以都要加进去,按照这种累加方法,我们需要按照“右-根-左”这中方式遍历树,即逆中序遍历,再通过递归直接进行累加和赋值。

class Solution {
public:
    int sum = 0;
    TreeNode* convertBST(TreeNode* root) {
        //按照右根左这种顺序遍历
        if (root == nullptr)//空节点直接结束本次递归
            return root;
        convertBST(root->right);//一直递归进去找最右边的值
        
        //中间节点
        sum = root->val + sum;
        root->val = sum;

        convertBST(root->left);//右边和根节点处理完,在处理左边的值

        return root;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值