代码随想录|day21|二叉树part07 ● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先

 530.二叉搜索树的最小绝对差 

链接:代码随想录

需要领悟一下二叉树遍历上双指针操作,优先掌握递归

 第一次做,理解错误,认为只需要以节点为单位,认为由于是二叉搜索树,所以中序遍历一定是一个连续的有序序列,则只需要比较root->left->val和root->val。

实际:理解错误,比如这种情况,要找到的是左子树的最大值,右子树的最小值,和root->val进行比较找最小值

,比如这种情况,仅仅以一个节点 为单位去比较它的左右节点是不全面的。

注:正确的方法是利用中序遍历,记录前一个结点,然后用pre和当下的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) {}
 * };
 */
 /*由于是二叉搜索树,所以中序遍历一定是一个连续的有序序列,则只需要比较root->left->val和root->val
 !理解错误,比如这种情况,要找到的是左子树的最大值,右子树的最小值,和root->val进行比较找最小值
 二叉搜索树采用中序遍历,其实就是一个有序数组。

在一个有序数组上求两个数最小差值,这是不是就是一道送分题了。

最直观的想法,就是把二叉搜索树转换成有序数组,然后遍历一遍数组,就统计出来最小差值了。
 */
class Solution {
public:
    int minn=10e5+1;
    TreeNode *pre=nullptr;
    int getMinimumDifference(TreeNode* root) {
        helper(root);
        return minn;

    }
    void helper(TreeNode *root)//中序遍历改进
    {
        if(root!=nullptr)
        {
            helper(root->left);
            if(pre!=nullptr)//在中序遍历的中间加入前一个结点与现有节点的比较
            {
                minn=min(minn,abs(pre->val-root->val));
            }
            pre=root;
            helper(root->right);

        }
        
    }
};

迭代做法,回忆中序遍历的迭代做法,利用栈:

/**
 * 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:
    int getMinimumDifference(TreeNode* root) {
        int minn=10e5+1;
        stack<TreeNode*>sta;
        TreeNode *node=root;
        TreeNode* pre = NULL;
        while(!sta.empty()|| node!=nullptr)
        {
            while(node!=nullptr)
            {
                sta.push(node);
                node=node->left;
            }
            node=sta.top();
            /*中序遍历位置
            cout<<node->val<<endl;*/
            if(pre!=nullptr)
            {
                minn=min(minn,abs(pre->val-node->val));
            }
            pre=node;
            sta.pop();
            node=node->right;
        }
        return minn;

    }
};

501.二叉搜索树中的众数 

链接:代码随想录

 

错误做法:错在递归结束时,pre停在最后一个节点,此时应该还有一个temp_cnt,需要最后和max_cnt 比较更新一下

/**
 * 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:
    int max_cnt=0;
    int temp_cnt=0;
    TreeNode *pre=nullptr;
    vector<int>v;
    vector<int> findMode(TreeNode* root) {
        helper(root);
        if(temp_cnt>max_cnt)
        {
                        while(!v.empty())
                        {
                            v.pop_back();
                        };
                        max_cnt=temp_cnt;
                        v.push_back(pre->val);
                    }
                    else if(temp_cnt==max_cnt)
                    {
                        max_cnt=temp_cnt;
                        v.push_back(pre->val);
                    }
                    
        
         return v;
    }
    void helper(TreeNode *root)
    {
        if(root!=nullptr)
        {
            helper(root->left);
            if(pre!=nullptr)
            {
                if(root->val==pre->val)
                {
                    temp_cnt++;
                }
                else
                {
                   if(temp_cnt>max_cnt)
                    {
                       v.clear();     // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
                        max_cnt=temp_cnt;
                        v.push_back(pre->val);
                    }
                    else if(temp_cnt==max_cnt)
                    {
                        max_cnt=temp_cnt;
                        v.push_back(pre->val);
                    }
                    
                    
                    temp_cnt=1;
                }

            }
            pre=root;
            helper(root->right);
        }
    }
};

 改进后:

class Solution {
// 结合前一道题来思考
public:
    int max_cnt=1;
    int temp_cnt=1;
    TreeNode *pre=nullptr;
    vector<int>v;
    vector<int> findMode(TreeNode* root) {
        helper(root);
        if(temp_cnt>max_cnt)
        {
                       v.clear();     // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
                        max_cnt=temp_cnt;
                        v.push_back(pre->val);
        }
        else if(temp_cnt==max_cnt)
        {
             max_cnt=temp_cnt;
             v.push_back(pre->val);
        }
         return v;
    }
    void helper(TreeNode *root)
    {
        if(root!=nullptr)
        {
            helper(root->left);
            if(pre!=nullptr)
            {
               cout<<pre->val<<" "<<root->val<<endl;
               
                if(root->val==pre->val)//如果和前一个结点值相等
                {
                    temp_cnt++;
                }
                else//如果和前一个结点值不相等
                {
                   if(temp_cnt>max_cnt)
                    {
                       v.clear();     // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
                        max_cnt=temp_cnt;
                        v.push_back(pre->val);
                    }
                    else if(temp_cnt==max_cnt)
                    {
                        max_cnt=temp_cnt;
                        v.push_back(pre->val);
                    }
                    
                    
                    temp_cnt=1;
                }

            }
            
            pre=root;
            helper(root->right);
        }
    }
};

最优的答案,这个答案不是计算上一个元素的连续相等元素个数,而是先pre=cur,然后计算比较cur->val和最大值,这样cur==nullptr时,能计算完所有元素的连续个数。

class Solution {
private:
    int count;
    int maxCount;
    TreeNode* pre;
    vector<int> result;
    void searchBST(TreeNode* cur) {
        if (cur == NULL) return ;

        searchBST(cur->left);       // 左
                                    // 中
        if (pre == NULL) { // 第一个节点
            count = 1;
        } else if (pre->val == cur->val) { // 与前一个节点数值相同
            count++;
        } else { // 与前一个节点数值不同
            count = 1;
        }
        pre = cur; // 更新上一个节点

        if (count == maxCount) { // 如果和最大值相同,放进result中
            result.push_back(cur->val);
        }

        if (count > maxCount) { // 如果计数大于最大值
            maxCount = count;
            result.clear();     // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
            result.push_back(cur->val);
        }

        searchBST(cur->right);      // 右
        return ;
    }

public:
    vector<int> findMode(TreeNode* root) {
        int count = 0; // 记录元素出现次数
        int maxCount = 0;
        TreeNode* pre = NULL; // 记录前一个节点
        result.clear();

        searchBST(root);
        return result;
    }
};

作者:代码随想录
链接:https://leetcode.cn/problems/find-mode-in-binary-search-tree/solutions/425776/501-er-cha-sou-suo-shu-zhong-de-zhong-shu-bao-li-t/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

236. 二叉树的最近公共祖先 

同类型的题还有

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先(链接:力扣

剑指 Offer 68 - II. 二叉树的最近公共祖先(链接:力扣)

链接:代码随想录

 

 完全没有了印象。。。灰溜溜的去看了题解.这道题显然是后序遍历,而且符合要求的节点要往上传,直到找到最近公共节

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
 //首先是,这道题我好像做过。其次是,我没什么印象了。确实做过,剑指offer原题
 //二叉树,(一个节点也可以是它自己的祖先)。
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==nullptr)return root;
        if(root==p||root==q)//当前遍历节点就是p或者q,直接返回当前节点
        {
            return root;
        }
        TreeNode *left=lowestCommonAncestor(root->left,p,q);//后序遍历,遍历左子树
        TreeNode *right=lowestCommonAncestor(root->right,p,q);//后序遍历,遍历右子树
        if(left!=nullptr && right!=nullptr)//左子树上找到p/q并传到了本节点,右子树也找到了,则本节点为公共节点,返回
        {
            return root;
        }
        else if(left!=nullptr)
        {
            return left;
        }
        else
        {
            return right;
        }


        
    }
};

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 

链接:力扣

 

 自己的做法,通过查看官方题解,又掌握一种。发现官方题解的递归遍历和我的思路相同,但是代码更为简洁,同时代码逻辑更绕

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

 //为了效率,简化了原本的二叉树的最近公共祖先
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==nullptr||root==p ||root==q)
        {
            return root;
        }

        TreeNode *left=nullptr,*right=nullptr;
        if(p->val<root->val ||q->val<root->val)
        {
           left=lowestCommonAncestor(root->left,p,q);
           
        }
        if(p->val> root->val || q->val> root->val)
        {
            right=lowestCommonAncestor(root->right,p,q);
        }

        if(left!=nullptr && right!=nullptr)
        {
            return root;
        }
        else if(left!=nullptr)
        {
            return left;
        }
        else
        {
            return right;
        }
       
        

        
    }
};

 官方解法:

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //终止条件:不需要,因为官方给了均存在与树中的条件
        //          即老子现在肯定是这两个乖孙子的公共祖先
        //递推操作:
        //第一种情况:
        if(root.val>p.val&&root.val>q.val){//看看是不是都是左儿子的后代
            return lowestCommonAncestor(root.left,p,q);//是的话就丢给左儿子去认后代(继续递归)
        }
        //第二种情况:
        if(root.val<p.val&&root.val<q.val){//不是左儿子的后代,看看是不是都是右儿子的后代
            return lowestCommonAncestor(root.right,p,q);//是的话就丢给右儿子去认后代(继续递归)
        }
        //第三种情况:
        //左儿子和右儿子都说我只认识一个,唉呀妈呀,那就是老子是你们最近的祖先,因为老子本来就是你们的公共的祖先
        //现在都只认一个,那就是老子是最近的。
        //其实第三种才是题目需要找到的解,所以返回,拜托我的祖先们也传一下(递归回溯返回结果),我才是他们最近的公共曾爷爷
        return root;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值