从不会 map 到轻松解决词频统计:一题吃透两种思路
在编程学习中,有一类题目特别适合打基础——看起来简单,但能引出非常关键的思维转变。“统计出现次数最多的单词”就是典型代表。 这篇内容不直接给出最优解,而是按照学习路径一步步展开: 先用最基础的方法解决问题 这样理解会更扎实,也更容易迁移到其他题目。 输入: 一个整数 接下来输入 要求: 忽略大小写(例如 Apple、apple、APPLE 视为同一个单词) 找出出现次数最多的单词 输出该单词(统一为小写) 保证答案唯一 既然要统计次数,可以采用最直接的办法: 对于每一个单词,去和后面的所有单词进行比较,统计相同的数量。 在此之前,需要先把所有单词统一转换成小写。 if (c >= 'A' && c <= 'Z') { 这是利用字符的 ASCII 规律完成转换。 #include <iostream> 这个写法可以得到正确答案,但存在一个现象: 同一个单词会被多次统计。 例如输入: 统计过程大致是: 第一次统计得到 3 第二次统计得到 2 第三次统计得到 1 虽然最终结果是正确的,但明显存在重复计算。 因为代码只关心最大值: 第一次已经得到最大值,后面的结果不会覆盖它。 这种方法的特点是: 思路简单直观 不依赖高级工具 存在重复计算 时间复杂度为 O(n²) 前面的做法本质是“不断比较”。 现在换一个角度: 每读取一个单词,就直接记录它出现的次数。 可以把它理解为一个统计表: 键(key):单词 值(value):出现次数 这行代码的含义是: 如果单词不存在,就创建并初始化为 0 然后加 1 完成一次统计 #include <iostream> 从实现方式来看: 第一种方法:通过比较来统计 第二种方法:通过记录来统计 从效率来看: 第一种方法:O(n²) 第二种方法:O(n log n) 从代码结构来看: 第一种方法:两层循环,逻辑分散 第二种方法:结构清晰,统计集中 关键差别不在语法,而在思维方式: 第一种方法是“比较思维” 当问题从“一个个比”转变为“直接记录”,代码就会变得更简单、更高效。 这类题目的正确学习路径是: 先用最基础的方法写出来,理解问题本质 如果一开始就直接使用高级工具,很容易“会写但不理解”。 这道题的价值不在于难度,而在于思维升级: 从重复比较,到一次统计 当能够自然想到用“记录”代替“比较”,说明已经迈入更高一层的编程理解。从不会
map 到轻松解决词频统计:一题吃透两种思路(C++详解)
再引入 map 优化
最后对比两种思路的本质区别一、题目描述(完整)
n(1 ≤ n ≤ 100)n 个单词二、第一种方法:不用 map 的基础解法
思路
大小写处理(不用 tolower)
c = c - 'A' + 'a';
}完整代码(基础版)
#include <string>
using namespace std;
int main() {
int n;
cin >> n;
string a[105];
// 输入 + 转小写
for (int i = 0; i < n; i++) {
cin >> a[i];
for (int j = 0; j < a[i].size(); j++) {
if (a[i][j] >= 'A' && a[i][j] <= 'Z') {
a[i][j] = a[i][j] - 'A' + 'a';
}
}
}
int maxCount = 0;
string ans;
// 统计
for (int i = 0; i < n; i++) {
int count = 1;
for (int j = i + 1; j < n; j++) {
if (a[i] == a[j]) {
count++;
}
}
if (count > maxCount) {
maxCount = count;
ans = a[i];
}
}
cout << ans << endl;
return 0;
}这个方法的问题
apple apple apple
为什么结果仍然正确
if (count > maxCount)
小结
三、思路升级:引入 map
思维变化
map 的作用
map<string, int> cnt;
核心代码
cnt[s]++;
完整代码(map版)
#include <map>
#include <string>
using namespace std;
int main() {
int n;
cin >> n;
map<string, int> cnt;
for (int i = 0; i < n; i++) {
string s;
cin >> s;
// 转小写
for (int j = 0; j < s.size(); j++) {
if (s[j] >= 'A' && s[j] <= 'Z') {
s[j] = s[j] - 'A' + 'a';
}
}
cnt[s]++;
}
string ans;
int maxCount = 0;
// 找最大值
for (auto &p : cnt) {
if (p.second > maxCount) {
maxCount = p.second;
ans = p.first;
}
}
cout << ans << endl;
return 0;
}四、两种方法对比
五、本质区别
第二种方法是“统计思维”六、学习建议
再引入 map,优化统计过程
最后再接触更高效的结构(如 unordered_map)七、总结
从手动计数,到自动管理

