set/map刷力扣题/(哈希表+排序类型)仿函数和捕获-两种方法解决
对于key的接收:set支持的key必须是小于比较(重载<运算符),因为底层是基于红黑树;
 unorder_set支持的key必须是转换成整型的(通过哈希映射)且支持等于比较(重载=运算符),底层是基于哈希表;
 迭代器差异:set是双向迭代器,支持++,–,set去重+升序;
 unordered_set是单向迭代器,仅仅支持++,unordered_set去重+无序
 性能分析:set底层是set底层红黑树的增、删、查、改操作的时间复杂度是 (O(log N))
 unordered_set底层哈希表的增、删、查操作平均时间复杂度是(O(1))
 O(1)是常数次时间复杂度。
 详细的:unorder_map和map的关系同上,都是从三个方面分析:对于key的接受,map要求Key支持小于比较,而unordered_map要求Key支持转成整形且支持等于比较,要理解unordered_map的这个两点要求
 得后续我们结合哈希表底层实现才能真正理解,也就是说这本质是哈希表的要求。
 迭代器差异unordered_map不去重+无序;map是去重+升序;性能分析:map底层是map底层红黑树的增、删、查、改操作的时间复杂度是 (O(log N))
 unordered_map底层哈希表的增、删、查操作平均时间复杂度是(O(1))
前k个高频元素
前k个高频元素
 
 解法:哈希+仿函数
 定义一个哈希表,用pair<int,int>进行封装,让nums中所有的元素都通过映射放置到哈希表中(统计数字的容器,计数),
 再申请一个新的vector容器vec来初始化成哈希表中放置的值,最后可以按照任意顺序返回(出现频率最高前k个元素),这里我们也可以先排序,将vec中的值排好序,不仅要拍好序,按照自然数的大小,还需要按照出现的次数多少,排在最前的只能是自然数小的+次数出现最多的(这里要调用哈希表中的计数)。
 要实现次数出现最多,可以实现一个仿函数,返回第二个参数second最大的。sort要调用仿函数排序。这样就实现了“sort自然数排序+次数最多”。
 最后设置一个vector容器来封装返回的结果,ret,遍历vec,取前k个元素,这前k个元素要去重。
class Solution {
public:struct kvfunction{bool operator()(const pair<int,int> &nums1,const pair<int,int> &nums2){return nums1.second>nums2.second;}};vector<int> topKFrequent(vector<int>& nums, int k) {unordered_map<int,int>up;for(auto &e:nums){up[e]++;}vector<pair<int,int>>vec(up.begin(),up.end());sort(vec.begin(),vec.end(),kvfunction());vector<int>ret;for(int i=0;i<k;i++){ ret.push_back(vec[i].first);}return ret;}
};
改进:不加仿函数,也即是不额外实现取得数字出现次数的函数,但是需要返回的元素(1.自然数顺序;2.次数最多;3.自行去重),还需要依靠哈希表实现。可以在sort内部参数加一个[ &] ,[& ] 意味捕获所有外部变量。即使在sort的生命周期内部没有哈希映射统计数字出现的个数,[& ]仍然可以从外部调用到up(哈希来统计次数)。
 [&] 表示 “以引用方式捕获所有外部变量”,其中就包括哈希表 up。
class Solution {
public:vector<int> topKFrequent(vector<int>& nums, int k) {unordered_map<int,int>up;for(auto &e:nums){up[e]++;}vector<pair<int,int>>vec(up.begin(),up.end());sort(vec.begin(),vec.end(),[&](const pair<int,int> &nums1,const pair<int,int> &nums2){return nums1.second>nums2.second;});vector<int>ret;for(int i=0;i<k;i++){ret.push_back(vec[i].first);}return ret;}
};
根据字符出现频率排序
根据字符出现频率排序
 
 题目解析:
 给定一个字符串 s ,根据字符出现的 频率 对其进行 降序排序 。一个字符出现的 频率 是它出现在字符串中的次数。
 解法:哈希+仿函数
问题:为什么这里的仿函数中要有构造函数?
仿函数是一个独立的结构体(类),它内部的成员变量(如存储频率的引用 up)默认不会自动关联外部的 up。必须通过构造函数,将外部的 up 作为参数传入仿函数,并赋值给内部的成员变量(这里是引用绑定),才能让仿函数 “拿到” 所需的频率数据。
class Solution {
public:struct kvfunction{// 存储外部哈希表的引用(关键:关联统计好的频率数据)unordered_map<char,int>up;// 构造函数:接收外部的哈希表并绑定引用kvfunction( unordered_map<char,int> &map):up(map){}bool operator()(const char & a,const char & b){return up[a] == up[b] ? a>b:up[a]>up[b];}};string frequencySort(string s) {unordered_map<char,int>up;//创建一个哈希映射,第一个参数是字符串,第二个参数是次数for(auto &e:s){up[e]++;}//遍历,统计出次数//排序,按照字符串的ASCII码值排序+出现次数sort(s.begin(),s.end(),[&](const char& a,const char& b){return up[a] == up[b] ? a>b : up[a]>up[b];});return s;}
};
先按字符出现次数(频率)排序,当频率相同时再按字符的 ASCII 码值排序
 “频率从高到低,频率相同则 ASCII 码从大到小”
 当两个字符的频率相等时(up[a] == up[b]),则按照字符的 ASCII 码值从大到小排序。例如,‘b’ 的 ASCII 码(98)大于 ‘a’(97),若两者频率相同,则 ‘b’ 排在 ‘a’ 前面。
改进:不加仿函数,用[&]以引用方式捕获所有外部变量。
class Solution {
public:string frequencySort(string s) {unordered_map<char,int>up;//创建一个哈希映射,第一个参数是字符串,第二个参数是次数for(auto &e:s){up[e]++;}//遍历,统计出次数//排序,按照字符串的ASCII码值排序+出现次数sort(s.begin(),s.end(),[&](const char& a,const char& b){return up[a] == up[b] ? a>b : up[a]>up[b];});return s;}
};
其中[&]意为从Up哈希统计次数中取得频次,[&]的存在使得sort可以向上取得char类型的字符在哈希映射中的次数。
 [&] 表示 “以引用方式捕获所有外部变量”,其中就包括哈希表 up。
前k个高频单词
前k个高频单词
 
 解法:详细见博主之前发过的一篇博客:set_map的实现+set/map加持秒杀高频算法题锻炼算法思维最后一题:
 这里更新另外一种可以不写仿函数的做法,在sort参数中引进[&],用于捕获外部元素。向上搜索到up哈希,用来 获取字符出现的频次。sort一方面可以实现一堆单词,首先按照频次进行比较,其次按照字典序进行排序。
 仿函数引进:来实现这道题:
class Solution {
public:struct kvFunction{bool operator()(const pair<string,int>w1,const pair<string,int>w2){return w1.second>w2.second;//表示次数多的排在前面}};vector<string> topKFrequent(vector<string>& words, int k) {map<string,int>countMap;for(auto& it:words){countMap[it]++;}//统计每一个单词出现的次数vector<pair<string,int>>v(countMap.begin(),countMap.end());//将一个键值对转换为一个vector容器,方便后序排序stable_sort(v.begin(),v.end(),kvFunction());//稳定排序(出现次数相同,保持原map中的字典序)vector<string>ret;for(int i=0;i<k;i++){ret.push_back(v[i].first);}return ret;}
};改进:引进[&]
class Solution {
public:vector<string> topKFrequent(vector<string>& words, int k) {unordered_map<string,int>up;for(auto &e:words){up[e]++;}vector<pair<string,int>>vec(up.begin(),up.end());sort(vec.begin(),vec.end(),[&](const pair<string,int> &words1,const pair<string,int> & words2){if(words1.second == words2.second)//如果频次相同,字典序小的在前面{return words1.first < words2.first;//字典序小的在前面}else{return words1.second>words2.second;}//否则频次多的在前面});vector<string>ret;for(int i=0;i<k;i++){ret.push_back(vec[i].first);}return ret;}
};