力扣数据结构14天学习计划day14

力扣98

力扣98—验证二叉搜索树

题意

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

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

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

 

解法1—中序遍历

二叉搜索树的中序遍历是递增的,在中序遍历的过程中,我们只需要判断上一个元素与当前元素的大小关系,如果上一个元素≥当前元素,则证明这不是一颗二叉搜索树,只需返回false即可。最后遍历完整颗二叉树后,返回true即可。

class Solution 
{
public:
    bool isValidBST(TreeNode* root) 
    {
        if(nullptr==root)
            return true;
        if(nullptr==root->left&&nullptr==root->right)
            return true;
        long pre = LLONG_MIN;
        stack<TreeNode*> st;
        while(!st.empty()||root)
        {
            while(root)
            {
                st.push(root);
                root=root->left;
            }
            root=st.top();
            st.pop();
            if(pre>=root->val)
            {
                return false;
            }
            pre=root->val;
            root=root->right;
        }
        return true;
    }
    
};

 力扣653—两数之和Ⅳ-输入 BST

力扣653

题意

给定一个二叉搜索树 root 和一个目标结果 k,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true 

解法1—哈希表

class Solution 
{
public:
    bool findTarget(TreeNode* root, int k) 
    {
        if(nullptr==root)
            return false;
        unordered_set<int>uset;
        stack<TreeNode*>st;
        while(!st.empty()||root)
        {
            while(root)
            {
                st.push(root);
                root=root->left;
            }
            root=st.top();
            st.pop();
            if(uset.count(k-root->val))
                return true;
            uset.insert(root->val);
            //if(uset.count(k-root->val)&&(k-root->val)!=root->val)
             //   return true;
            root=root->right;
        }
        return false;
    }
};

 解法2—中序遍历+双指针

二叉搜索数的中序遍历会得到一个递增序列,然后利用双指针求出这个递增序列是否存在两个数相加得到目标值。

class Solution 
{
private:
    vector<int>vec;
public:
    void in_order(TreeNode* root)
    {
        if(nullptr==root)
            return;
        in_order(root->left);
        vec.push_back(root->val);
        in_order(root->right);
    }
    bool findTarget(TreeNode* root, int k) 
    {
        if(nullptr==root)
            return false;

        in_order(root);

        //双指针
        int i=0,j=vec.size()-1;
        while(i<j)
        {
            int sum=vec[i]+vec[j];
            if(sum<k)
                i++;
            else if(sum>k)
                j--;
            else
                return true;
        }
        return false;

        /*
        unordered_set<int>uset;
        stack<TreeNode*>st;
        while(!st.empty()||root)
        {
            while(root)
            {
                st.push(root);
                root=root->left;
            }
            root=st.top();
            st.pop();
            if(uset.count(k-root->val))
                return true;
            uset.insert(root->val);
            //if(uset.count(k-root->val)&&(k-root->val)!=root->val)
            //  return true;
            root=root->right;
        }
        return false;
        */


    }
};

力扣235—二叉搜索树的最近公共祖先

力扣235

题意

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

 

解法1—非递归(适用于二叉搜索树)

我们从根节点开始遍历,具体的算法流程:

  1. 如果两个节点值都小于根节点,说明他们都在根节点的左子树上,我们往左子树上找
  2. 如果两个节点值都大于根节点,说明他们都在根节点的右子树上,我们往右子树上找
  3. 如果一个节点值大于根节点,一个节点值小于根节点,说明他们他们一个在根节点的左子树上一个在根节点的右子树上,那么根节点就是他们的最近公共祖先节点

 


class Solution 
{
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        //判断p和q的位置
        int p_val=p->val,q_val=q->val,root_val=root->val;

        //如果root的值与p、q的值之差,相乘结果大于0,说明p和q都在root的同一侧
        while((root_val-p_val)*(root_val-q_val)>0)
        {
            // 如果root值比他们大,说明p、q都在root左侧,否则在root右侧
            root=root_val>p_val?root->left:root->right;
            root_val=root->val;
        }
    //如果root的值与p、q的值之差,相乘结果小于0,说明p和q都在root的两侧,root就是他们最近的祖先节点
    //如果相乘结果为0,说明p和q至少有一个就是root
        return root;
        
    }
};

 解法2—递归(适用于二叉搜索树)


class Solution 
{
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        //递归解决
        if((root->val-p->val)*(root->val-q->val)<=0)
        {
            //如果相乘结果小于等于0,说明p、q在root两侧
            //或者 p、q有一个就是root
            return root;
        }
        //否则,p、q同时在root的一侧
        root=root->val>p->val?root->left:root->right;
        return lowestCommonAncestor(root,p,q);

        /*
        非递归解决
        //判断p和q的位置
        int p_val=p->val,q_val=q->val,root_val=root->val;

        //如果root的值与p、q的值之差,相乘结果大于0,说明p和q都在root的同一侧
        while((root_val-p_val)*(root_val-q_val)>0)
        {
            // 如果root值比他们大,说明p、q都在root左侧,否则在root右侧
            root=root_val>p_val?root->left:root->right;
            root_val=root->val;
        }
    //如果root的值与p、q的值之差,相乘结果小于0,说明p和q都在root的两侧,root就是他们最近的祖先节点
    //如果相乘结果为0,说明p和q至少有一个就是root
        return root;
        */
        
    }
};

解法3—二叉树和二叉搜索树都适合


class Solution 
{
public:
    //函数作用是,在以 root 为根的这棵树里面,如果能找到p就返回p出去,能找到q,就返回q出去
    //如果p和q都可以找到的话,就返回root 
    TreeNode* find_p_or_q(TreeNode* root,TreeNode* p,TreeNode* q)
    {
        if(root==nullptr||root==p||root==q)
            return root;
        TreeNode* left=find_p_or_q(root->left,p,q);
        TreeNode* right=find_p_or_q(root->right,p,q);
        if(nullptr!=left&&nullptr!=right)
        {
            //如果在root为根的这棵树里面,左右子树中都能够找到p和q
            //说明,p、q分布在这颗树的左右两侧,root就是他们的公共祖先
            return root;
        }
        else if(nullptr==left&&nullptr==right)
        {
            //在左右子树中都没有找到p和q,说明这棵树中没有他们的公共祖先
            return nullptr;
        }
        else if(nullptr==left)
        {
            //如果在左子树中没找到p或者q
            //直接返回右子树结果即可
            return right;
        }
        else if(nullptr==right)
        {
            //同上
            return left;
        }
        return nullptr;
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        //二叉树和二叉搜索树都适合的解法
        return find_p_or_q(root,p,q);


        //递归解决
        /*
        if((root->val-p->val)*(root->val-q->val)<=0)
        {
            //如果相乘结果小于等于0,说明p、q在root两侧
            //或者 p、q有一个就是root
            return root;
        }
        //否则,p、q同时在root的一侧
        root=root->val>p->val?root->left:root->right;
        return lowestCommonAncestor(root,p,q);
        */

        /*
        非递归解决
        //判断p和q的位置
        int p_val=p->val,q_val=q->val,root_val=root->val;

        //如果root的值与p、q的值之差,相乘结果大于0,说明p和q都在root的同一侧
        while((root_val-p_val)*(root_val-q_val)>0)
        {
            // 如果root值比他们大,说明p、q都在root左侧,否则在root右侧
            root=root_val>p_val?root->left:root->right;
            root_val=root->val;
        }
    //如果root的值与p、q的值之差,相乘结果小于0,说明p和q都在root的两侧,root就是他们最近的祖先节点
    //如果相乘结果为0,说明p和q至少有一个就是root
        return root;
        */
        
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

心之所向便是光v

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

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

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

打赏作者

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

抵扣说明:

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

余额充值