leetcode刷题22——二叉搜索树系列

1.不同的二叉搜索树
给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
考察知识点:动态规划
结题思路:假设n个节点存在二叉排序树的个数是G(n),1为根节点,2为根节点,…,n为根节点;当1为根节点时,其左子树节点个数为0,右子树节点个数为n-1,同理当2为根节点时,其左子树节点个数为1,右子树节点为n-2,所以可得G(n) = G(0)G(n-1)+G(1)(n-2)+…+G(n-1)*G(0)。

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n+1,0);
        dp[0]=1;dp[1]=1;
        for(int i=2;i<=n;++i)
            for(int j=1;j<=i;++j)
                dp[i]+=dp[j-1]*dp[i-j];
        return dp[n];
    }
};

2.不同的二叉搜索树 II
给定一个整数 n,生成所有由 1 … n 为节点所组成的 二叉搜索树 。
考察知识点:DFS

class Solution {
public:
    vector<TreeNode*> generateTrees(int n) {
        if(n==0)    return {};
        return dfs(1,n);
    }
    vector<TreeNode*> dfs(int left,int right)
    {
        vector<TreeNode*> ans;
        if(left>right)
        {
            ans.push_back(nullptr); //*
            return ans;
        }
        for(int i=left;i<=right;++i)
        {
            vector<TreeNode*> leftnode=dfs(left,i-1);
            vector<TreeNode*> rightnode=dfs(i+1,right);
            for(auto lnode:leftnode)
                for(auto rnode:rightnode){
                    TreeNode* node=new TreeNode(i); //*
                    node->left=lnode;
                    node->right=rnode;
                    ans.push_back(node);
                }
        }    
        return ans;       
    }
};

解释:对于连续整数序列[left, right]中的一点i,若要生成以i为根节点的BST,则有如下规律:
i左边的序列可以作为左子树结点,且左儿子可能有多个,所以有vector<TreeNode *> left_nodes = generate(left, i - 1);;
i右边的序列可以作为右子树结点,同上所以有vector<TreeNode *> right_nodes = generate(i + 1, right);;
产生的以当前i为根结点的BST(子)树有left_nodes.size() * right_nodes.size()个,遍历每种情况,即可生成以i为根节点的BST序列;
然后以for循环使得[left, right]中每个结点都能生成子树序列。

一旦left大于right,则说明这里无法产生子树,所以此处应该是作为空结点返回:ans.push_back(NULL); return ans;;
返回[left, right]中生成的所有子树序列ans。

3.验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数;
节点的右子树只包含大于当前节点的数;
所有左子树和右子树自身必须也是二叉搜索树。
考察知识点:中序遍历
思路:中序遍历为升序

class Solution {
public:
    long pre=(long)INT_MIN-1;
    bool isValidBST(TreeNode* root) {
        if(!root)   return true;
        bool l=isValidBST(root->left);
        bool m=(root->val > pre);
        pre=root->val;
        bool r=isValidBST(root->right);
        return l&&m&&r;
    }
};

4.恢复二叉搜索树
给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?
考察知识点:中序遍历
思路:我们对错误的二叉树进行中序遍历,那我们按顺序访问到的数应该是按顺序排列的 。
那如果对两个节点交换了顺序,那一定有两个地方是不满足:前一个元素 < 当前元素 < 后一个元素
所以我们使用两个全局变量在遍历过程中记录这两个节点 最后对他们进行交换

class Solution {
public:
    TreeNode *t1,*t2,*pre;
    void recoverTree(TreeNode* root) {
        inorder(root);
        int temp=t1->val;
        t1->val=t2->val;
        t2->val=temp;
    }
    void inorder(TreeNode* root){
        if(root==nullptr)   return;
        inorder(root->left);
        if(pre!=nullptr && pre->val>root->val)
        {
            if(t1==nullptr) t1=pre;
            t2=root;
        }
        pre=root;
        inorder(root->right);
    }
};

5.将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
考察知识点:递归
思路:选择中间位置左边的数字作为根节点,则根节点的下标为mid=(left+right)/2。

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return helper(0,nums.size()-1,nums);
    }
    TreeNode* helper(int left,int right,vector<int>& nums)
    {
        if(left>right) return nullptr;
        int mid=(left+right)/2;
        TreeNode* root=new TreeNode(nums[mid]);
        root->left=helper(left,mid-1,nums);
        root->right=helper(mid+1,right,nums);
        return root;
    }
};

6.有序链表转换二叉搜索树
给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
考察知识点:递归

class Solution {
public:
    TreeNode* sortedListToBST(ListNode* head) {
        return helper(head,nullptr);
    }
    TreeNode* helper(ListNode* head, ListNode* end)
    {
        if(head==end)   return nullptr;
        ListNode *slow=head,*fast=head;
        while(fast!=end && fast->next!=end) 
        {
            slow=slow->next;
            fast=fast->next->next;
        }
        TreeNode *root=new TreeNode(slow->val);
        root->left=helper(head,slow); //*
        root->right=helper(slow->next,end);
        return root;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

给算法爸爸上香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值