代码随想录算法训练营第21天 | 二叉树part07:● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先

530 二叉搜索树的最小绝对差, 关键:二叉搜索树和顺序有关的,全都用中序

本题中序套模板,思路秒出。但是传var这里让我学到了。一开始写的是traverse(TreeNode* node, TreeNode* prev, int &min),发现就是prev没传对。后来prev改成global var就对了。

TreeNode* prev;
    void traverse(TreeNode* node,int &min){
        if(node==nullptr) return;
        if(node->left) traverse(node->left, min);
        if(prev!=nullptr) {
            min=std::min(min,std::abs(node->val-prev->val));
        }
        prev=node;
        if(node->right) traverse(node->right,  min);

    }
    int getMinimumDifference(TreeNode* root) {
        //二叉树和顺序有关的,都要用中序遍历
        int min=INT_MAX;
        prev=nullptr;
        traverse(root, min);
        return min;


    }

我原来传TreeNode* prev的时候总以为自己已经在传地址了,其实不是,可以把TreeNode* 整体理解成一个data type,然后再加上ref才是对的,所有func才在公用一个,TreeNode* & prev

就加一个&符号,WA变AC。不过我看代码随想录都是直接变成global var,其实挺好的,很方便了

void traverse(TreeNode* node, TreeNode* &prev, int &min){
        if(node==nullptr) return;
        if(node->left) traverse(node->left, prev, min);
        
        if(prev) min=std::min(min,std::abs(node->val-prev->val));
        prev=node;
        if(node->right) traverse(node->right, prev, min);
    }
    int getMinimumDifference(TreeNode* root) {
        //二叉树和顺序有关的,都要用中序遍历
        int min=INT_MAX;
        TreeNode* prev=nullptr;
        traverse(root, prev, min);
        return min;
    }

迭代法直接套中序模板,这里就不写了

501 二叉搜索树中的众数

一下想到两种思路,但具体细节思路都略有困惑,看了随想录解答

1 放好再做。本实现熟悉了如何map变vec进行sort

    map<int,int> nodemap;
    void traverse(TreeNode* node){
        if(node==nullptr) return;
        if(node->left) traverse(node->left);
        nodemap[node->val]++;
        if(node->right) traverse(node->right);
    }

    bool static cmp(const pair<int,int> &a, const pair<int,int> &b){
        return a.second>b.second;
    }

    vector<int> findMode(TreeNode* root) {
        
        //1 模板方法:遍历全部放map,用库函数 
        traverse(root);

        vector<pair<int,int>> vec(nodemap.begin(),nodemap.end());
        sort(vec.begin(),vec.end(),cmp);

        vector<int> res;
        for(int i=0;i<vec.size();i++){
            if(vec[i].second==vec[0].second){
                res.push_back(vec[i].first);
            }
        }
        return res;
    }

 2. 边放边做

这里有一个不用遍历两遍找所有众数的技巧

 我这个方法自己写了好久,快一个小时,全是逻辑小问题,越写越乱。不想写了,先把随想录的解放在这里:之后抽时间还是要再自己做一次

private:
    int maxCount = 0; // 最大频率
    int count = 0; // 统计频率
    TreeNode* pre = NULL;
    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) {
        count = 0;
        maxCount = 0;
        TreeNode* pre = NULL; // 记录前一个节点
        result.clear();

        searchBST(root);
        return result;
    }

236 Lowest Common Ancestor 最近公共祖先

第一次做公共祖先的题,不会,思路只能出来是后序+回溯。看了思路自己实现的:

主要思路 分两个大类:1 自己不当自己的祖先,那就看左右sub同时都有p/q那就是了

2 自己当自己的祖先,逻辑见代码

实现主要出现的问题和要点:

​​​​​​​1.TreeNode *leftn=nullptr;TreeNode *rightn=nullptr;一开始一个case都过不了,就是因为没初始化这俩,也太重要了

2. 递归不能像迭代一样在中间结束,所以确实 返回什么都可以。返回nullptr能让尽快的结束

 

TreeNode* res=nullptr;
    
    TreeNode* traverse(TreeNode* node,TreeNode* &p, TreeNode* &q){
       
        if(node==nullptr) return node;
        TreeNode *leftn=nullptr;
        TreeNode *rightn=nullptr;
       
        if (node->left) leftn=traverse(node->left,p,q);
        if (node->right) rightn=traverse(node->right,p,q);
        
        //自己当自己的祖先
        if((leftn||rightn)&&(node==p||node==q)&& res==nullptr){
            res=node;
            return nullptr;//return anything could end
        }
        if(node==p||node==q) return node;
    
        
        if(leftn && rightn && res==nullptr){
           res=node;
           return nullptr;//return anything could end
           
        }
        else if(leftn && rightn==nullptr){
            return leftn;
        }
        else if(rightn && leftn==nullptr){
            return rightn;
        }

        return nullptr;

    }
    TreeNode* lowestCommonAncestor(TreeNode* &root, TreeNode* p, TreeNode* q) {
       traverse(root,p,q);
       return res;
    }

上面是我的把两种情况分开讨论的思路。下面是随想录的精简版,能把自己是不是祖先两种情况合并在一起处理:把公共祖先和p,q混在一起返回

if (left != NULL && right != NULL) return root;对于这句,是return 祖先,那在另外的subtree就不可能找到pq了,下次另一边(可能是left或right)一定是null,所以这句话满足了一次后,以后必不可能再满足了,只会随着后序不断往root传,最终做为最后的结果。

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == q || root == p || root == NULL) 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 right;
        else if (left != NULL && right == NULL) return left;
        else  { //  (left == NULL && right == NULL)
            return NULL;
        }

    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值