题解:学而思编程 数位排序

【题目来源】

学而思编程:数位排序

【题目描述】

小猴对一个数的数位之和很感兴趣,今天他要按照数位之和给序列\(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

【核心思想】

  1. 问题分析:给定 \(n\) 个互不相同的正整数,要求按数位和升序排序,数位和相同时按数值大小升序排序。这是一个自定义排序问题,关键在于设计比较函数,先比较数位和,再比较原数值。

  2. 算法选择

    • 数位和计算:通过取模和除法逐位求和
    • 自定义比较函数cmp(x, y) 先比较 cal(x)cal(y),相等时比较 xy
    • 标准排序:使用 sort 配合自定义比较函数
  3. 关键步骤

    • 初始化:读取 \(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):按自定义规则排序
      • 输出排序后的数组
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \log n \times d)\)\(d\) 为数字位数(数位和计算),排序 \(O(n \log n)\),每次比较 \(O(d)\)
    • 空间复杂度:\(O(n)\),存储数组
  5. 自定义排序的核心思想

    • 多级排序键:第一关键字为数位和,第二关键字为原数值,比较函数按优先级依次判断
    • 稳定排序替代:若使用稳定排序,可先按数值排序,再按数位和排序;但自定义比较函数更直接高效
    • 数位和计算:利用十进制特性,通过 %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
posted @ 2026-07-05 14:29  团爸讲算法  阅读(11)  评论(0)    收藏  举报