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

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

题目链接:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差

当我们充分了解了二叉搜索树的性质后,这道题就十分简单了。

我们可以将二叉树通过中序递归组成一个数组,由于二叉搜索树的性质,这是一个递增的数组,然后只要通过一次遍历,就能找到两个数的最小差值了。

代码如下:

class Solution {
public:
    vector<int> vec;
    void traversal(TreeNode* root){//构建数组
        if(root==NULL) return;
        traversal(root->left);
        vec.push_back(root->val);
        traversal(root->right);
    }
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        int result=INT_MAX;
        if(vec.size()<2){
            return 0;
        }
        for(int i=1;i<vec.size();i++){//遍历
            if(vec[i]-vec[i-1]<result){
                result=vec[i]-vec[i-1];
            }
        }
        return result;
    }
};

 当然,这道题也可以不使用构建升序数组的方法,而是才用双指针法,一个指针root指向当前节点,另一个指针pre只向上一次递归所在的节点,然后用root->val-pre->val,其实与构建数组相比,思路时一样的,由于还是采用的中序递归,所以其实两个指针就相当于数组中的vec[i]、vec[i-1],只是省去了建立新数组的步骤,代码如下:

class Solution {
public:
    int result=INT_MAX;
    TreeNode* pre=NULL;
    void traversal(TreeNode* root)
    {
        if(root==NULL) return;
        traversal(root->left);
        if(pre!=NULL){
        result=min(result,root->val-pre->val);
        }
        pre=root;
        traversal(root->right);
    }
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return result;
    }
};

501.二叉搜索树中的众数

 题目链接:501. 二叉搜索树中的众数 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:不仅双指针,还有代码技巧可以惊艳到你! | LeetCode:501.二叉搜索树中的众数

 这道题我的第一想法就是管他是二叉什么树,直接无脑遍历一遍,然后用map记录元素出现次数就可以了。

class Solution {
public:
    void traversal(TreeNode* root,unordered_map<int,int> &map)//遍历,放入map中
    {
        if(root==NULL) return;
        map[root->val]++;
        traversal(root->left,map);
        traversal(root->right,map);
    }
    bool static cmp(const pair<int,int>&a,const pair<int,int>&b)//自定义排序顺序
    {
        return a.second>b.second;
    }
    vector<int> findMode(TreeNode* root) {
        unordered_map<int,int> map;
        traversal(root,map);
        vector<int> result;
        vector<pair<int,int>> vec(map.begin(),map.end());//将map放入二维数组中
        sort(vec.begin(),vec.end(),cmp);//将数组排序
        result.push_back(vec[0].first);//先存第一个
        for(int i=1;i<vec.size();i++)
        {
            if(vec[i].second==vec[0].second){
                result.push_back(vec[i].first);只要后面的个数和第一个相等,就再加进result中
            }
            else break;
        }
        return result;
    }
};

当然,我们也可以靠二叉搜索树的性质——父节点和它的左右子节点可能相等,所以我们也可以使用双指针法,如上题,pre记录上一个节点,root记录当前节点,只要相等那么count++,并把元素放进result数组中,如果不相等,就重置count,继续递归,并用maxcount记录递归过程中最大的count,如果出现更大的count就清空result,放入新的元素。

代码如下:

class Solution {
public:
    TreeNode* pre=NULL;
    int count=0;
    int maxcount=0;//记录递归中最大的count
    vector<int> result;//记录结果
    void traversal(TreeNode* root)//中序递归
    {
        if(root==NULL) return;
        traversal(root->left);
        if(pre==NULL) count=1;//说明到达叶子节点,这是第一个数
        else if(root->val==pre->val) count++;
        else count=1;
        pre=root;
        if(count==maxcount) result.push_back(root->val);//有相同频率的数字,就加入数组中
        if(count>maxcount){//有更高频率的数字,就重置数组
            maxcount=count;
            result.clear();
            result.push_back(root->val);
        }
        traversal(root->right);
        return;  
    }
    vector<int> findMode(TreeNode* root) {
        traversal(root);
        return result;
    }
};

二叉树的最近公共祖先

 题目链接:236. 二叉树的最近公共祖先 - 力扣(LeetCode)

文章链接:代码随想录 (programmercarl.com)

视频链接:自底向上查找,有点难度! | LeetCode:236. 二叉树的最近公共祖先

这道题稍微难了点,求最近公共祖先,我们就要从底部向上遍历,所以只能用后续递归来解决。而由于这是一个递归回溯的过程,我们如果找到了p、q还需要不断地向上返回他们的节点就相当于将p、q节点不断向上传递的过程(可能有点抽象......)。代码如下:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL||root==p||root==q) return root;
        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);
        if(left!=NULL&&right!=NULL) return root;//如果左右孩子都不为NULL,说明root就是共同祖先
        else if(left!=NULL&&right==NULL) return left;//如果一边有右边无,有两种情况,第一种指遍历到p或者q,正在返回该节点,第二种情况就是已经找到共同祖先,正在向上返回祖先的节点,
        else if(left==NULL&&right!=NULL) return right;
        else return NULL;
    }
};

其实还包括了一种情况,p是q的公共祖先或q是p的公共祖先,这种情况其实隐含在上面的代码里了,假如p是q的公共祖先,我们通过递归,递归到了p,就直接通过

if(root==NULL||root==p||root==q) return root;这一串代码返回了,p后面的节点q自然就遍历不到了,直接返回q节点了。

Day21 打卡成功,耗时3小时再接再厉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值