代码随想录训练营第二十一天打卡|530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先

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

1.因为二叉搜索树中序遍历是个非递减序列,所以最小绝对值差一定在中序遍历的相邻结点取到。朴素思想是把二叉树的中序遍历用数组输出,然后处理这个数组找到最小绝对值差。(以迭代法求取数组为例)

/**
 * 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 min=INT_MAX;
vector<int> inorderTraversal(TreeNode* root){
    vector<int> result;
    stack<TreeNode*> st;
    TreeNode* cur=root;
    while(cur||!st.empty()){
        if(cur){
            st.push(cur);
            cur=cur->left;
        }
        else{
            cur=st.top();
            st.pop();
            result.push_back(cur->val);
            cur=cur->right;
        }
    }
    return result;
}
    int getMinimumDifference(TreeNode* root) {
        vector<int> result=inorderTraversal(root);
        for(int i=0;i<result.size()-1;i++){
            if(result[i+1]-result[i]<min)
            min=result[i+1]-result[i];
        }
        return min;
    }
};

2.其实在中序遍历二叉搜索树的过程中就可以顺带求出最小值,以递归法为例

/**
 * 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 result = INT_MAX;
TreeNode* pre = NULL;
void traversal(TreeNode* cur) {
    if (cur == NULL) return;
    traversal(cur->left);   // 左
    if (pre != NULL){       // 中
        result = min(result, cur->val - pre->val);
    }
    pre = cur; // 记录前一个
    traversal(cur->right);  // 右
}
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return result;
    }
};

501.二叉搜索树中的众数

1.一个朴素思想就是遍历这个二叉树并记录每个元素出现的频率,再按照频率从大到小排序,输出频率最大的一个或多个元素值。(普适方法,所有的二叉树都能处理)

/**
 * 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://普通法(一般二叉树也能处理)
void searchBST(TreeNode* cur,unordered_map<int,int>& map){//遍历函数
    if(cur==NULL) return;
    map[cur->val]++;
    searchBST(cur->left,map);
    searchBST(cur->right,map);
    return;
}
bool static cmp(pair<int,int> a,pair<int,int> b){//比较函数
    return a.second>b.second;
}
    vector<int> findMode(TreeNode* root) {
        unordered_map<int,int> umap;
        searchBST(root,umap);
        vector<pair<int,int>> copy;
        for(auto x:umap)//map不能直接排序,需要先复制到一个同类型数组中
        copy.push_back({x.first,x.second});
        sort(copy.begin(),copy.end(),cmp);
        vector<int> result;
        for(auto y:copy){//将频率最高的所有元素加入到返回数组中
            if(y.second==copy[0].second)
            result.push_back(y.first);
        }
        return result;
    }
};

2.在朴素思想中,我们没有用到二叉搜索树的特性,即它的中序遍历是一个单调的序列。有着相同元素值的结点一定是相邻的,那我们就可以在中序遍历的过程中记录最大频率对应的元素值。

/**
 * 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 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(cur->val==pre->val) count++;//相邻元素值相等,频率++
    else count=1;//不相等则重新从1开始计算频率
    pre=cur;
    if(count==maxcount) result.push_back(cur->val);//出现次数最多的元素有多个则一起加进去
    if(count>maxcount){//出现了频率更高的元素,则更新最大值,清除数组,加入新元素
        maxcount=count;
        result.clear();
        result.push_back(cur->val);
    }
    searchBST(cur->right);//右
    return;
}
    vector<int> findMode(TreeNode* root) {
        searchBST(root);
        return result;
    }
};
/**
 * 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://迭代法
    vector<int> findMode(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* cur=root;
        int maxcount=0;
        int count=0;
        TreeNode* pre=NULL;
        vector<int> result;
        while(cur||!st.empty()){
            if(cur){
                st.push(cur);
                cur=cur->left;
            }
            else{
                cur=st.top();
                st.pop();
                if(pre==NULL) count=1;
                else if(cur->val==pre->val) count++;
                else count=1;
                pre=cur;
                if(count==maxcount) result.push_back(cur->val);
                if(count>maxcount){
                maxcount=count;
                result.clear();
                result.push_back(cur->val);
                }
                cur=cur->right;
            }
        }
        return result;
    }
};

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

1.朴素思想:先构造一个函数判断一个结点是不是另一个结点的祖先,我采用的是先序遍历递归。

之后层序遍历这个二叉树,是两个结点的公共祖先就另返回结点接收。逐层遍历二叉树,出现新的公共祖先结点就更新返回结点,最后更新的祖先节点一定是最近的公共祖先结点。(理论存在,实践过是过了,执行时间1300多ms,把我自己都看笑了)

/**
 * 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://暴力层序法
bool isAncestor(TreeNode* cur,TreeNode* node){//判断公共祖先函数
    if(cur==NULL) return false;
    if(cur==node) return true;
    if(isAncestor(cur->left,node)) return true;
    if(isAncestor(cur->right,node)) return true;
    return false;
}
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        TreeNode* result=NULL;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()){
            int size=que.size();
            for(int i=0;i<size;i++){
                TreeNode* cur=que.front();
                que.pop();
                if(isAncestor(cur,p)&&isAncestor(cur,q))
                result=cur;//有新的祖先结点就更新
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
        }
        return result;
    }
};

2.1300多ms实在是有些丢人,有什么办法能减少运行时间呢?有的,那就是剪枝。因为公共结点可能是一个结点本身,所以我优先处理了p是q的祖先和q是篇的祖先,进行了剪枝。结果奇迹出现了,提交结果出现了一个双超过99%的评价!剪枝大法好啊!

/**
 * 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://暴力层序法
bool isAncestor(TreeNode* cur,TreeNode* node){
    if(cur==NULL) return false;
    if(cur==node) return true;
    if(isAncestor(cur->left,node)) return true;
    if(isAncestor(cur->right,node)) return true;
    return false;
}
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(p->left==q||p->right==q) return p;//剪枝
        if(q->left==p||q->right==p) return q;
        if(isAncestor(p,q)) return p;
        if(isAncestor(q,p)) return q;
        TreeNode* result=NULL;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()){
            int size=que.size();
            for(int i=0;i<size;i++){
                TreeNode* cur=que.front();
                que.pop();
                if(isAncestor(cur,p)&&isAncestor(cur,q))
                result=cur;
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
        }
        return result;
    }
};

3.递归法,为什么采用后序遍历?因为递归逻辑要求我们这样做,先处理左右子树,根据左右子树的结果进行返回。

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

今日总结:剪枝大法好啊!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值