统计每个数的出现次数,再按频次降序、数值升序排序输出。
OJ: shumeng
题目 ID: CSP201503B
难度:入门
标签:排序计数
日期: 2026-07-31 16:21
形式化题目
给定
思路
先看一个不借助计数数组的小数据基准:先收集互不相同的数字,再按“次数最多、值最小”的规则反复选出下一个要输出的数字。
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-31 16:21
* update_at: 2026-08-17 22:51
*/
// brute.cpp:小数据基准,枚举不同数字并反复选择当前应输出的数字。
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> numbers(n);
for (int i = 0; i < n; i++) cin >> numbers[i];
vector<int> values;
for (int i = 0; i < n; i++) {
bool exists = false;
for (int j = 0; j < (int)values.size(); j++) {
if (values[j] == numbers[i]) exists = true;
}
if (!exists) values.push_back(numbers[i]);
}
vector<int> count(values.size(), 0);
for (int i = 0; i < (int)values.size(); i++) {
for (int j = 0; j < n; j++) {
if (numbers[j] == values[i]) count[i]++;
}
}
vector<int> used(values.size(), 0);
for (int round = 0; round < (int)values.size(); round++) {
int best = -1;
for (int i = 0; i < (int)values.size(); i++) {
if (used[i]) continue;
if (best == -1 || count[i] > count[best] ||
(count[i] == count[best] && values[i] < values[best])) {
best = i;
}
}
used[best] = 1;
cout << values[best] << ' ' << count[best] << '\n';
}
return 0;
}brute.cpp 用两重循环统计频率,再每次扫描选出当前最优条目,逻辑最贴合题意,适合作为对拍基准。
正式做法分两步:
- 统计:给出的数都是
的非负整数,直接用大小为 的计数数组 count_value记录每个数字的出现次数。 - 排序:把所有出现过的数字封装成
(value, count)条目,按比较器排序——先让较大的count在前,count相同时让较小的value在前。
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-31 16:21
* update_at: 2026-08-17 22:51
*/
#include <bits/stdc++.h>
using namespace std;
int count_value[1005]; // count_value[x] 表示数字 x 出现的次数
struct Item {
int value; // 数字本身
int count; // 出现次数
};
// 排序规则:次数大的在前,次数相同时数值小的在前。
bool compare_item(const Item &left, const Item &right) {
if (left.count != right.count) return left.count > right.count;
return left.value < right.value;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int value;
cin >> value;
count_value[value]++;
}
vector<Item> items;
for (int value = 0; value <= 1000; value++) {
if (count_value[value] > 0) {
Item current = {value, count_value[value]};
items.push_back(current);
}
}
sort(items.begin(), items.end(), compare_item);
for (int i = 0; i < (int)items.size(); i++) {
cout << items[i].value << ' ' << items[i].count << '\n';
}
return 0;
}复杂度
- 时间:统计为
,设不同数字数为 ,排序为 。 - 空间:
。
总结
有重复元素的排序题,先压缩为“值和频次”的条目,再把题意的主关键字(次数降序)和次关键字(数值升序)完整写进比较器即可。计数数组比 map 更快,适合值域小的题目。