[TOC]

一、二叉搜索树的增删改查

700. 二叉搜索树中的搜索(简单难度)

class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        //终止条件
        if(root==NULL)return NULL;
        //处理节点
        if(root->val==val) return root;
        //有条件的递归调用
        if(val<root->val)return searchBST(root->left,val);
        if(val>root->val)return searchBST(root->right,val);
        return root;
    }
};

701. 二叉搜索树中的插入操作(中等难度)

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        //终止条件和处理节点
        if(root==NULL){
            TreeNode* newNode=new TreeNode(val);
            return newNode;
        }
        //有条件的递归
        if(val<root->val) root->left=insertIntoBST(root->left,val);
        if(val>root->val) root->right=insertIntoBST(root->right,val);
        return root;
    }
};

450. 删除二叉搜索树中的节点(中等难度)

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        //终止条件(如果没有找到删除节点)
        if(root==NULL) return NULL;
        //处理节点(如果找到删除节点)
        if(root->val==key){
            //如果删除节点是叶子节点,返回NULL
            if(root->left==NULL&&root->right==NULL) return NULL;
            //如果删除节点只有右节点,返回右节点
            else if(root->left==NULL&&root->right!=NULL)return root->right;
            //如果删除节点只有左节点,返回左节点
            else if(root->left!=NULL&&root->right==NULL)return root->left;
            //如果删除节点有左节点和右节点,删除root,右节点替补,左节点接到右节点的最左侧节点上
            else{
                //找到其右子树的最左侧节点
                TreeNode* cur=root->right;
                while(cur->left!=NULL){
                    cur=cur->left;
                }
                //最左侧节点指向删除节点的左节点
                cur->left=root->left;
                //安置删除节点的右节点
                //TreeNode* tmp=root;
                root=root->right;
                //delete tmp;
                return root;
            }
        }
        //有条件的递归调用
        if(root->val>key)root->left=deleteNode(root->left,key);
        if(root->val<key)root->right=deleteNode(root->right,key);
        return root;
    }
};

669. 修剪二叉搜索树(中等难度)

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        //终止条件
        if(root==NULL)return NULL;
    	//当前值需要裁剪
        if(root->val<low)//如果当前值小于裁剪区间,说明需要修剪
        {
            return trimBST(root->right,low,high);//左节点一定不符合,只需要检查右节点
        }
        else if(root->val>high)//如果当前值大于裁剪区间,说明需要修剪
        {
            return trimBST(root->left,low,high);//右节点一定不符合,只需要检查左节点
        }
    	//当前值不需要裁剪,但是其子节点可能需要
        root->left=trimBST(root->left,low,high);
        root->right=trimBST(root->right,low,high);
        return root;
    }
};

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

235. 二叉搜索树的最近公共祖先(简单难度)

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先(简单难度)

方法一:直接使用普通二叉树的方法

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL) return NULL;
        if(root->val==p->val||root->val==q->val) return root;
        // 有条件递归
        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);
        if(left!=NULL&&right!=NULL) return root;
        if(left!=NULL&&right==NULL) return left;
        if(left==NULL&&right!=NULL) return right;
        return NULL;
    }
};

方法一:有序递归子区间

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL)return NULL;
        //如果p和q的值都小于当前节点的值,说明最近公共祖先在当前节点的左子树上
        if(p->val<root->val&&q->val<root->val) return lowestCommonAncestor(root->left,p,q);
        //如果p和q的值都小于当前节点的值,说明最近公共祖先在当前节点的右子树上
        if(p->val>root->val&&q->val>root->val) return lowestCommonAncestor(root->right,p,q);
        //否则说明最近公共祖先就是当前节点
        return root;
    }
};

897. 递增顺序搜索树(简单难度)

剑指 Offer II 052. 展平二叉搜索树(简单难度)

class Solution {
public:
    TreeNode* pre;
    void dfs(TreeNode* cur){
        if(cur==nullptr) return;
        dfs(cur->left);
        // 处理节点
        pre->right=cur;
        cur->left=nullptr;
        pre=cur;
        dfs(cur->right);
    }
    TreeNode* increasingBST(TreeNode* root) {
        TreeNode* myHead=new TreeNode(-1);
        pre=myHead;
        dfs(root);
        return myHead->right;
    }
};

剑指 Offer 54. 二叉搜索树的第k大节点(简单难度)

class Solution {
public:
    int res=0;//最终结果
    int count=0;//计数
    void dfs(TreeNode* root,int k){
        if(root==NULL) return ;
        //倒序:右,根,左
        dfs(root->right,k);
        ++count;
        if(k==count) {
            res=root->val;
            return;
        }
        dfs(root->left,k);
    }
    int kthLargest(TreeNode* root, int k) {
        dfs(root,k);
        return res;
    }
};

230. 二叉搜索树中第K小的元素(中等难度)

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

class Solution {
public:
    int res=0;//最终结果
    int count=0;//计数
    void dfs(TreeNode* root,int k){
        if(root==NULL) return ;
        //正序:左,根,右
        dfs(root->left,k);
        // 进入节点
        ++count;
        if(k==count) {
            res=root->val;
            return;
        }
        dfs(root->right,k);
    }
    int kthSmallest(TreeNode* root, int k) {
        dfs(root,k);
        return res;
    }
};

剑指 Offer 33. 二叉搜索树的后序遍历序列(中等难度)

class Solution {
public:
    // 后序遍历序列[左子树区间,右子树区间,根节点]
    bool verifyPostorder(vector<int>& postorder) {
        return dfs(postorder,0,postorder.size()-1);
    }
    // 在[left,right]中进行递归遍历,
    bool dfs(vector<int>& postorder,int left,int right){
        // 终止条件(right是根节点,此时只有一个节点)
        if(left>=right) return true;
        // 遍历[left,right],查找第一个大于根节点的节点,此为右区间第一个节点
        int m=left;
        while(m<=right){
            if(postorder[m]>=postorder[right]) break;
            else m++;
        }
        // 遍历右子树区间[m,right-1],查看是否有比right小的值
        for(int i=m;i<right;i++){
            if(postorder[i]<=postorder[right])
                return false;
        }
        // 继续遍历左子树区间[left,m-1]和右子树区间[m,right-1]
        return dfs(postorder,left,m-1)&&dfs(postorder,m,right-1);

    }
};

285. 二叉搜索树中的中序后继(中等后继)

剑指 Offer II 053. 二叉搜索树中的中序后继(中等后继)

class Solution {
public:
    vector<TreeNode*> arr;//中序遍历数组
    void dfs(TreeNode* root){
        if(root==NULL) return;
        dfs(root->left);
        arr.push_back(root);
        dfs(root->right);
    }
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        // 中序递归,得到数组
        dfs(root);
        // 遍历数组,找到该节点
        int i=0;
        while(i<arr.size()&&arr[i]->val!=p->val)++i;
        // 如果i正好是最后一个节点,返回null
        if(i==arr.size()-1) return NULL;
        // 如果i不是最后一个节点,返回其后继
        else return arr[i+1];
    }
};

三、中序遍历相关

98. 验证二叉搜索树(中等难度)

class Solution {
public:
    vector<int> arr;
    void dfs1(TreeNode* root){
        if(root==nullptr) return;
        dfs1(root->left);
        arr.push_back(root->val);
        dfs1(root->right);
    }
    long long maxVal = LONG_MIN; // 左子树中的默认最大值,测试数据中有LONG_MIN
    bool dfs2(TreeNode* root){
        if(root==nullptr) return true;
        bool left=dfs2(root->left);
        // 中序遍历,maxVal为left子树中的最大值
        if (maxVal < root->val) maxVal = root->val;
        else return false;
        bool right=dfs2(root->right);
        return left&&right;
    }
    bool isValidBST(TreeNode* root) {
        // 方法一
        // dfs1(root);
        // for(int i=1;i<arr.size();++i){
        //     if(arr[i-1]>=arr[i]) return false;
        // }
        // return true;
        // 方法二
        return dfs2(root);
    }
};

426. 将二叉搜索树转化为排序的双向链表(中等难度)

class Solution {
private:
    Node* pre=NULL; // 当前访问节点的前一个节点
    Node* head=NULL;// 双向循环链表的头结点
public:
    Node* treeToDoublyList(Node* root) {
        if(root==NULL) return NULL;
        // 采用中序遍历的方式遍历二叉搜索树,修改为双向链表
        dfs(root);
        // 修改为循环链表
        head->left = pre;//头结点指向尾结点
        pre->right = head;//尾结点指向头结点
        return head;
    }
    // 中序遍历
    void dfs(Node* cur){
        // 终止条件
        if(cur==NULL) return;
        // 递归左节点 
        dfs(cur->left);
        // 处理节点head,pre,cur
        if(pre) pre->right=cur;// 如果pre不为空,说明双向链表上已经有节点,其指向当前节点
        else head=cur;// 如果pre为空,说明双向链表没有节点,设置头结点
        cur->left=pre;// 当前节点指向上一个
        pre=cur;// 更新上一个节点
        // 递归右节点
        dfs(cur->right);
    }
};