目录
三、衍生容器:multiset和multimap(使用较少)
1.给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。
2.输入一个英文句子,把句子中的单词(不区分大小写)按出现次数按从多到少把单词和次数在屏幕上输出来,次数一样的按照单词小写的字典序排序输出,要求能识别英文单词和句号。
一、相同点
- 底层数据结构
- map和set底层均采用平衡搜索二叉树(红黑树)实现
- 红黑树是一种自平衡二叉查找树,能保证最坏情况下基本操作的时间复杂度
- 查找操作的时间复杂度均为O(logN)
- 示例:当数据量为100万时,查找次数最多为20次(log₂10⁶≈20)
- 两者都基于key值进行排序和插入操作
- 默认采用升序排列(可通过比较函数修改)
- 示例:插入顺序为5,3,7时,实际存储顺序为3,5,7
- 2.自动去重特性
- set会自动过滤重复元素
- 示例:插入1,2,2,3后,set中实际存储为1,2,3
- map会忽略相同key的插入操作
- 示例:已存在key=5的记录时,再次插入key=5的数据会被忽略
int arr[] = {1,2,3,1,1,2};
set<int> se(arr, arr+6); // 自动去重后元素为{1,2,3}
map<int,int> mp;
mp.insert({1,2});
mp.insert({1,3}); // 因key重复,此操作被忽略
- 其他共同特性
- 均属于STL关联容器
- 迭代时保持有序性
- 支持反向迭代器(rbegin/rend)
- 内存分配采用动态增长方式
-
插入后的key值不可修改(可删除但不可更改);
-
自动排序特性:
- 默认按升序排列
- 可通过中序遍历获取有序序列
二、主要区别
-
头文件包含不同:map使用#include<map>,set使用#include<set>
-
访问方式差异:
- map支持[]操作符进行数据插入和访问
- set未重载[]操作符
示例说明:
map<string,string> mp;
mp["insert"]; // 若不存在则自动插入该键值对
mp["insert"] = "插入"; // 修改对应键的值
- 内部结构不同:
- map<T,T>存储的是pair<T,T>键值对
- set<T>直接存储数据T
三、衍生容器:multiset和multimap(使用较少)
主要特性:
- 支持存储重复元素
- find操作会返回中序遍历时遇到的第一个匹配元素
四、有关map的oj题目
1.给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。
示例:
输入: words = ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
注意,按字母顺序 "i" 在 "love" 之前。
代码+注释:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<map>
#include<algorithm>//sort的头文件算法头文件
#include<vector>
#include<string>
using namespace std;
class myfunc
{
public:
bool operator()(const pair<string, int>& i, const pair<string, int>& j)
{
return i.second > j.second ||
i.second == j.second && i.first < j.first;//先比较second大的排前面
//要是相等就比较first把较小的排前面;
}
};//仿函数控制sort的比较逻辑
class Solution {
public:
vector<string> topKFrequent(vector<string>& words, int k) {
map<string, int> a;
for (auto e : words)
{
a[e]++;//map类的[]使用会返回value也就是key对应的map里的第二个存储值
}
vector<pair<string, int>> v(a.begin(), a.end());//由于sort只能遍历随机迭代器
//所以我们只能把map里的值其内核pair传到vector里面比较
sort(v.begin(), v.end(), myfunc());//不使用pair自带的比较不符合题意;自己写仿函数进行比较
vector<string> vv;
for (int i = 0;i < k;i++)
{
/*vv[i] = v[i].first;*/
vv.push_back(v[i].first);//把排好队的string输入
}
return vv;
}
};
int main()
{
Solution s;
vector<string> wd = { "i","i","a","a","wapd","b","b","b"};
vector<string> w = s.topKFrequent(wd, 3);
for (auto e : w)
{
cout << e << " ";
}//返回k个数量最多的单词
}
第一题的进阶版本:
2.输入一个英文句子,把句子中的单词(不区分大小写)按出现次数按从多到少把单词和次数在屏幕上输出来,次数一样的按照单词小写的字典序排序输出,要求能识别英文单词和句号。
示例:
输入:
A blockhouse is a small castle that has four openings through which to shoot.
复制
输出:
a:2
blockhouse:1
castle:1
four:1
has:1
is:1
openings:1
shoot:1
small:1
that:1
through:1
to:1
which:1
代码+注释:
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
using namespace std;
class func
{
public:
bool operator()(const pair<string, int> i, const pair<string, int> j)
{
return i.second > j.second || i.second == j.second && i.first < j.first;
}
};//控制大小比较
int main() {
map<string, int> mp;
string str;
getline(cin, str);//直接输入一整行的字符进入str中;
for (int c = 0;c < str.size();c++)
{
if (str[c] != '.' && str[c] != ' ' && str[c] < 'a')
{
str[c] = str[c] + 32;
}
}//将大写字母全部转换为小写两者差32;
size_t i = 0;
size_t vsize = 0;
size_t p = 0;
p = str.find(' ');//找到第一个空格
while (p != str.find('.'))//不是句号就不停
{
string word(str.begin() + i, str.begin() + p);//把句子拆分成单词
mp[word]++;//插入map树中并进行计数;
i = p + 1;//下一个单词开头
p = str.find(' ',i);//下一个单词末尾的空格;
if (p == string::npos)//要是上面的p没有找到空格,就说明只剩下一个单词了这个单词后必是句号
{
p = str.find('.');
string word(str.begin() + i, str.begin() + p);
mp[word]++;
}
}
vector<pair<string, int>> ma(mp.begin(), mp.end());//以vector容器存储ma里的值便于遍历
sort(ma.begin(), ma.end(), func());//sort用仿函数func()方法排序;
for (int n = 0;n < ma.size();n++)
{
cout << ma[n].first << ':' << ma[n].second << endl;//输出排好的所有值;
}
}
4261

被折叠的 条评论
为什么被折叠?



