C++ 前K个高频单词的六种解法

目录

 大堆

小堆

vector+sort

 vector+stable_sort

multimap

set/multiset

与GPT的对话

1.对于比较类型中 < 运算符重载的理解

2.map有稳定性的说法吗

​编辑

3.为什么map和set类的仿函数后面要加const来修饰*this

5.关于名词的理解

6.匿名对象对类要求

7.map和set的基本知识


 

分析:其实就是选择一种容器排序,需要能够存放一对元素,可以想到使用map,unordered_map,vector,pair

堆:

        个人理解:比较的时候左边是parent,右边是child,所以当仿函数是小于号时候,也就是孩子大,接下来进行交换,大的自然往就上走;对于一般的线性结构小于升序,大于降序,我觉得是这样的nums[right]<nums[left]

 大堆

 可以建大堆,也可以小堆

1.大堆,就是大的在根,这样的话就不能建立一个大小为K的堆,只能全部梭哈

2. 比较逻辑是根据题意来的,个数优先,其次在个数相同的时是字典序,所以肯定有个或(“ | | ”)

class Solution {
public:
    typedef pair<string, int> PSI;
    struct cmp
    {
        bool operator()(const PSI& kv1, const PSI& kv2)
        {
            return kv1.second < kv2.second || kv1.second == kv2.second 
                && kv1.first > kv2.first;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> m;
        for(auto& e : words)
            m[e]++;
        priority_queue<PSI, vector<PSI>, cmp> heap(m.begin(), m.end());

        vector<string> ret;
        for(int i = 0; i < k; i++)
            ret.push_back(heap.top().first), heap.pop();
        return ret;
    }
};

小堆

 1.如果堆里的K个元素就是符合条件的,那么只能小根堆;遇到新的元素先push进来,如果size() > K那么就pop()

2.在输出方面:因为只能取出堆顶元素,如果选择正着存,可以使用ret.push_back() + reverse

如果是想一步到位那么就放到对应的下标里,注意:需要提前开空间初始化(也就是赋值),因为单单开空间是不能使用下标来访问元素(其实是很有道理的,没有初始化这个数据就是不属于你,就是不应该有访问权限,可是我是修改这个位置的值,不是访问啊;修改的前提是有访问的权限,有访问权限才有修改资格),可以使用resize或者创建对象的时候就初始化

 3.cmp与大堆相反

class Solution {
public:
    typedef pair<string, int> PSI;
    struct cmp
    {
        bool operator()(const PSI& kv1, const PSI& kv2)
        {
            return kv1.second > kv2.second || kv1.second == kv2.second 
                && kv1.first < kv2.first;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> m;
        for(auto& e : words)
            m[e]++;
        priority_queue<PSI, vector<PSI>, cmp> heap;
        for(auto& e : m)
        {
            heap.push(e);
            if(heap.size() > k) heap.pop();
        }
        // vector<string> ret(k);
        // for(int i = k - 1; i >= 0; i--)
        //     ret[i] = heap.top().first, heap.pop();
        vector<string> ret;
        for(int i = 0; i < k; i++)
            ret.push_back(heap.top().first), heap.pop();
        reverse(ret.begin(), ret.end());
        return ret;
    }
};

vector+sort

class Solution {
public:
    typedef pair<string, int> PSI;
    struct cmp
    {
        bool operator()(const PSI& kv1, const PSI& kv2) 
        {
            return kv1.second > kv2.second || kv1.second == kv2.second
                && kv1.first < kv2.first;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> count_map;
        for(auto& v : words)
            count_map[v]++;
        vector<pair<string, int>> v(count_map.begin(), count_map.end());
        sort(v.begin(), v.end(), cmp());

        vector<string> ret;
        for(int i = 0; i < k; i++)
            ret.push_back(v[i].first);
        return ret;
    }
};

 vector+stable_sort

稳定性指的是元素在原始序列中的相对顺序,这里不需要写个数相同情况下字典序的比较,是因为map默认就是less<key>,如果掉默认的greater(),那么遇到比较时传的是pair的运算符重载

class Solution {
public:
    typedef pair<string, int> PSI;
    struct cmp
    {
        bool operator()(const PSI& kv1, const PSI& kv2) 
        {
            return kv1.second > kv2.second;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> count_map;
        for(auto& v : words)
            count_map[v]++;
        vector<pair<string, int>> v(count_map.begin(), count_map.end());
        stable_sort(v.begin(), v.end(), cmp());

        vector<string> ret;
        for(int i = 0; i < k; i++)
            ret.push_back(v[i].first);
        return ret;
    }
};

multimap

1. 不熟练->写出这样的map<pair<string, int>, cmp>类型,导致下面push_back报错(没有匹配的函数),那么也就不能用map的迭代器了,类型不配了

2. 

cmp传的参数只能是第一次参数,所以int必须在string前面,那么为什么保证了字典序?我觉得是因为第一个map

问题:会发现仿函数后面有const,前面的容器为什么不需要?map和set就要?

class Solution {
public:
    typedef pair<string, int> PSI;
    struct cmp
    {
        bool operator()(const int key1, const int key2) const
        {
            return key1 > key2;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> count_map;
        for(auto& str : words)
            count_map[str]++;
        // map<pair<string, int>, cmp> sort_map(count_map.begin(), count_map.end());

        // multimap<string, int, cmp> sort_map(count_map.begin(), count_map.end());
        // multimap<int, string, cmp> sort_map(count_map.begin(), count_map.end());
        multimap<int, string, cmp> sort_map;
        for(auto& e : count_map)
            sort_map.insert({e.second, e.first});
            // sort_map.insert(make_pair(e.second, e.first));

        vector<string> ret;
        auto it = sort_map.begin();
        for(int i = 0; i < k; i++)
        {
            ret.push_back(it->second);
            it++;
        }
        return ret;
    }
};

set/multiset

map和set的取值只能通过迭代器

这个地方的multiset和set效果是一样的,因为每一pair都是不一样的

class Solution {
public:
    typedef pair<string, int> PSI;
    struct cmp
    {
        bool operator()(const PSI& kv1, const PSI& kv2) const
        {
            return kv1.second > kv2.second || kv1.second == kv2.second && kv1.first < kv2.first;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string, int> count_map;
        for(auto& str : words)
            count_map[str]++;

        set<PSI, cmp> sort_set(count_map.begin(), count_map.end());
        //multiset<PSI, cmp> sort_set(count_map.begin(), count_map.end());

        vector<string> ret;
        auto it = sort_set.begin();
        for(int i = 0; i < k; i++)
        {
            ret.push_back(it->first);
            it++;
        }
        return ret;
    }
};

与GPT的对话

1.对于比较类型中 < 运算符重载的理解

升序是less,重载的是 < (小于号)

2.map有稳定性的说法吗

3.为什么map和set类的仿函数后面要加const来修饰*this

我没怎么看懂,以现在的功力只能记住map和set中的比较类型的()运算符重载的成员函数,需要加上const

5.关于名词的理解

6.匿名对象对类要求

7.map和set的基本知识

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值