题解:学而思编程 数位排序
【题目来源】
学而思编程:数位排序
【题目描述】
小猴对一个数的数位之和很感兴趣,今天他要按照数位之和给序列\(a_1,a_2,\dots,a_n\)排序。当两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时,将数值小的排在前面,保证所有整数互不相同。
例如,\(1001\) 排在 \(99\) 前面,因为 \(1001\) 的数位之和是 \(2\),而 \(99\) 的数位之和 \(18\)。
又如,\(2\) 排在 \(101\) 前面,因为它们的数位之和相同,而 \(2\) 小于 \(101\)。
请你帮助小猴完成这个任务。
【输入】
第一行,包含一个正整数 \(n\);
第二行,包含 \(n\) 个正整数 \(a_1,a_2,\dots,a_n\)。
【输出】
一行,空格隔开的 \(n\) 个整数,表示排序之后的序列。
【输入样例】
5
2 4 1 5 3
【输出样例】
1 2 3 4 5
【核心思想】
-
问题分析:给定 \(n\) 个互不相同的正整数,要求按数位和升序排序,数位和相同时按数值大小升序排序。这是一个自定义排序问题,关键在于设计比较函数,先比较数位和,再比较原数值。
-
算法选择:
- 数位和计算:通过取模和除法逐位求和
- 自定义比较函数:
cmp(x, y)先比较cal(x)与cal(y),相等时比较x与y - 标准排序:使用
sort配合自定义比较函数
-
关键步骤:
- 初始化:读取 \(n\) 和数组 \(a[1..n]\)
- 数位和函数
cal(x):sum = 0- 当
x > 0时循环:sum += x % 10:累加末位数字x /= 10:去掉末位
- 返回
sum
- 自定义比较函数
cmp(x, y):- 若
cal(x) != cal(y):返回cal(x) < cal(y)(数位和小的排前面) - 否则:返回
x < y(数位和相等时,数值小的排前面)
- 若
- 排序并输出:
sort(a + 1, a + n + 1, cmp):按自定义规则排序- 输出排序后的数组
-
时间/空间复杂度:
- 时间复杂度:\(O(n \log n \times d)\),\(d\) 为数字位数(数位和计算),排序 \(O(n \log n)\),每次比较 \(O(d)\)
- 空间复杂度:\(O(n)\),存储数组
-
自定义排序的核心思想:
- 多级排序键:第一关键字为数位和,第二关键字为原数值,比较函数按优先级依次判断
- 稳定排序替代:若使用稳定排序,可先按数值排序,再按数位和排序;但自定义比较函数更直接高效
- 数位和计算:利用十进制特性,通过
%10和/10逐位分离,适用于任意正整数 - 互异性保证:题目保证所有整数互不相同,避免了相等元素时的排序歧义
- 适用于"多关键字排序"类问题,自定义比较函数是 C++ 中实现复杂排序规则的标准方法
【解题思路】

【算法标签】
其他排序
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, a[100005];
int cal(int x) // 计算数位和
{
int sum = 0;
while (x>0) {
sum += x%10;
x /= 10;
}
return sum;
}
bool cmp (int x, int y)
{
if (cal(x)!=cal(y)) { // 数位和不同时
return cal(x)<cal(y); // 小的排前面
}
return x < y; // 否则数值小的排前面
}
int main()
{
cin >> n;
for (int i=1; i<=n; i++) cin >> a[i]; // 输入n个数
sort(a+1, a+n+1, cmp); // 按照自定义方式排序
for (int i=1; i<=n; i++) cout << a[i] << " ";
return 0;
}
【运行结果】
5
2 4 1 5 3
1 2 3 4 5
浙公网安备 33010602011771号