【Leetcode二叉搜索树的属性四】501.二叉搜索树中的众数 451.根据字符出现频率排序(包含很多代码的实现技巧)

Leetcode 501.二叉搜索树中的众数

1.问题描述

在这里插入图片描述

2.解决方案

解法一:按普通二叉树的做法

总结:

这个思路很简单就是遍历一遍统计频率第二遍把最高的加入结果集,但是难的是代码的实现技巧
1.下面这两条语句可以直接写成一条,因为uMap即使没加入一个k-v,也可以直接uMap[k]++,所以优化版本在遍历的同时便统计了频率而不是先遍历再统计

if(uMap.find(item)==uMap.end()) uMap[item]=1;
else uMap[item]++;

2.就是对频率排序这个操作是个问题,下图说得很清楚了,这也算是个代码实现技巧了,因为一开始我统计完频率是不知道该怎么优雅的把众数统计出来的!

在这里插入图片描述


原始:
class Solution {
public:
    vector<int> inorder;
    void tran(TreeNode* root){
        if(root== nullptr) return;

        tran(root->left);
        inorder.push_back(root->val);
        tran(root->right);
    }
    bool static cmp(pair<int,int> a,pair<int,int> b){
        //频率由高到低
        return a.second>b.second;
    }
    vector<int> findMode(TreeNode* root) {
        //1.想到了
        tran(root);
        unordered_map<int,int> uMap;
        for (auto item: inorder) {
            if(uMap.find(item)==uMap.end()) uMap[item]=1;
            else uMap[item]++;
        }
        //2.这我就没想到了
        vector<pair<int,int>> vec(uMap.begin(),uMap.end());
        sort(vec.begin(),vec.end(),cmp);
        vector<int> ans;
        ans.push_back(vec[0].first);
        for(int i=1;i<vec.size();i++){
            if(vec[i].second==vec[0].second) ans.push_back(vec[i].first);
            else break;
        }
        return ans;
    }
};


优化:
class Solution1 {
public:
    void tran(TreeNode* root,unordered_map<int,int>& uMap){
        if(root== nullptr) return;

        tran(root->left,uMap);
        uMap[root->val]++;
        tran(root->right,uMap);
    }
    bool static cmp(pair<int,int> a,pair<int,int> b){
        //频率由高到低
        return a.second>b.second;
    }
    vector<int> findMode(TreeNode* root) {
        //1.想到了
        unordered_map<int,int> uMap;
        tran(root,uMap);

        //2.这我就没想到了
        vector<pair<int,int>> vec(uMap.begin(),uMap.end());
        sort(vec.begin(),vec.end(),cmp);
        vector<int> ans;
        ans.push_back(vec[0].first);
        for(int i=1;i<vec.size();i++){
            if(vec[i].second==vec[0].second) ans.push_back(vec[i].first);
            else break;
        }
        return ans;
    }
};


Java:思路差不多,主要是用的集合框架完成的对value的排序
public class lc501 {
    Map<Integer, Integer> map = new HashMap<>();
    public void getFrequency(TreeNode root) {
        if(root==null) return;
        map.put(root.val, map.getOrDefault(root.val, 0)+1);
        getFrequency(root.left);
        getFrequency(root.right);
    }
    public int[] findMode(TreeNode root) {
        //
        if(root==null) return new int[0];
        getFrequency(root);
        Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
        ArrayList<Map.Entry<Integer, Integer>> list = new ArrayList<>(entries);
        Collections.sort(list, new Comparator<Map.Entry<Integer, Integer>>() {
            @Override
            public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                //默认value升序
                //return o1.getValue().compareTo(o2.getValue());

                //按照value降序
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        //
        List<Integer> ans = new ArrayList<>();
        ans.add(list.get(0).getKey());
        for (int i = 1; i <= list.size()-1; i++) {
            if(list.get(i).getValue()!=list.get(i-1).getValue()) break;
            ans.add(list.get(i).getKey());
        }
        int[] array = ans.stream().mapToInt(Integer::intValue).toArray();
        return array;
    }
}


解法二:按二叉搜索树遍历一遍出结果的做法

总结:

思路呢这里已经说得很清楚了,我也就不多说,其实思路不是很难就是更新有更大的count就清空结果集再加入,然而其实难得是代码实现技巧
1.第一个技巧用pre记录递归遍历的前一个结点,在这篇博客第一次使用530. 二叉搜索树的最小绝对差,非常好用,初始化为nullptr然后每次对空不空做出判断就好!
2.这题目和530. 二叉搜索树的最小绝对差思路很像啊,就是我们不需要把中序序列求出来再作文章,我们直接在递归过程中进行一个前后元素比较!
3.既然是中序遍历那肯定大体框架不会变tran(cur->left)…中间节点处理…tran(cur->right)
4.再实现逻辑的时候有个大致的思路,我们声明了四个全局变量

int maxCount=0;
int count=0;
vector<int> ans;
TreeNode* pre= nullptr;

那么是不是我们再对情况使用if做一个分类之后就要想这种情况对这四个全局变量要作何处理,每一种情况都这么想就不会出错了!
5.代码实现小错误,我写代码不喜欢写else,一般都是两个if这也导致一种错误情况的出现,在if的expr判断的变量如果在第一个if被改变,那很有可能第二个if的判断就不是一开始的那个变量了,比如这段代码,所以在两个if作为完全集考虑的时候一定考虑第一个if是否对if的条件变量做出了改变如果有,及时处理,换成else或者如果在for里面加上continue等!

if(pre== nullptr){
    count=1;
    maxCount=1;
    ans.push_back(cur->val);
    pre=cur;
}
//if(pre!= nullptr){ //代码小错误
else{

6.至于一遍出结果这个思路还是很不错的,建议多看!


在这里插入图片描述
在这里插入图片描述


代码:
class Solution2 {
public:
    int maxCount=0;
    int count=0;
    vector<int> ans;
    TreeNode* pre= nullptr;
    void tran(TreeNode* cur){
        if(cur== nullptr) return;

        tran(cur->left);

        if(pre== nullptr){
            count=1;
            maxCount=1;
            ans.push_back(cur->val);
            pre=cur;
        }
        //if(pre!= nullptr){ //代码小错误
        else{
            if(pre->val==cur->val){
                count++;
                pre=cur;
            }
            if(pre->val!=cur->val){
                count=1;
                pre=cur;
            }

            if(count==maxCount){
                ans.push_back(cur->val);
            }
            if(count>maxCount){
                maxCount=count;
                ans.clear();
                ans.push_back(cur->val);
            }
        }

        tran(cur->right);
    }
    vector<int> findMode(TreeNode* root) {
        tran(root);
        return ans;
    }
};


解法三:迭代

老生常谈了,用迭代代替递归实现中序遍历,这边就不给出了暂时!




Leetcode 451.根据字符出现频率排序

1.问题描述

在这里插入图片描述

2.解决方案

简单的按照频率排序,然后从高到低依次写入结果集

class Solution {
    public String frequencySort(String s) {
        //统计频率
        HashMap<Character, Integer> map = new HashMap<>();
        for(char c : s.toCharArray()){
            map.put(c, map.getOrDefault(c, 0) + 1);
        }
        //按照频率排序从高到低
        List<Map.Entry<Character, Integer>> list = new ArrayList<>(map.entrySet());
        Collections.sort(list, (map1, map2) -> (map2.getValue() - map1.getValue()));
        //从高到低构造结果集
        StringBuilder sb = new StringBuilder();
        for(var entry : list){
            int fre = entry.getValue();
            while(fre-->0){
                sb.append(entry.getKey());
            }
        }
        return sb.toString();
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值