【算法刷题】蓝桥杯:0星际争霸(大数比较 + 多关键字自定义排序)

【算法刷题】蓝桥杯:0星际争霸(大数比较 + 多关键字自定义排序)

📌 题目链接与描述

  • 题目名称:0星际争霸
  • 题目链接 :蓝桥云课 - 0星际争霸
  • 数据规模 : 1 ≤ n ≤ 1000 1 \le n \le 1000 1≤n≤1000, 1 ≤ a i ≤ 10 1000 1 \le a_i \le 10^{1000} 1≤ai≤101000(包含前导零,保留原格式输出)
  • 核心问题 :给定 n n n 个数字字符串,按照以下三级优先级 进行升序排序:
    1. 第一优先级:字符串内部的"逆序对"数量(较小的排前面)。
    2. 第二优先级:逆序对相同时,按照数值大小排序(即字符串长度较短的排前面)。
    3. 第三优先级:长度相同时,按照字典序从小到大排序。

🔍 核心思路解析

1. 内部逆序对的计算

对于长度为 L L L 的字符串 S S S,统计内部所有满足 i < j i < j i<j 且 S i > S j Si > Sj Si>Sj 的字符对数量。

  • 由于字符串长度 L ≤ 1000 L \le 1000 L≤1000,采用双重循环遍历的复杂度为 O ( L 2 ) \mathcal{O}(L^2) O(L2)。
  • 1000 2 / 2 = 5 × 10 5 1000^2 / 2 = 5 \times 10^5 10002/2=5×105 次比较,运行耗时极短,完全不会超时。

2. 多关键字自定义排序规则(避坑关键)

当逆序对数量相同时,需要按数值大小排序。因为题目数据规模高达 10 1000 10^{1000} 101000,必须使用字符串存储:

  • 不能直接比较字典序 :例如字符串 "9" 和 "10",如果仅使用字典序比较,"10" < "9" 会得出错误结论;必须先比较字符串长度 ,长度短的数值小("9" 长度为 1,"10" 长度为 2)。
  • 排序三步走 :
    逆序对 r e v ⟶ 字符串长度 s i z e ( ) ⟶ 字典序 v a l \text{逆序对 } rev \longrightarrow \text{字符串长度 } size() \longrightarrow \text{字典序 } val 逆序对 rev⟶字符串长度 size()⟶字典序 val

💻 C++ 完整 AC 代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

// 存储结构体
struct W {
    string val; // 原始字符串
    long long rev; // 内部逆序对数量
};

// 1. 计算单个字符串内部的逆序对数量
long long d_count(const string& a) {
    long long cnt = 0;
    int n = a.size();
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (a[i] > a[j]) {
                cnt++;
            }
        }
    }
    return cnt;
}

// 2. 自定义多关键字排序规则
bool cmp(const W& w1, const W& w2) {
    // 优先级 1:逆序对数量升序
    if (w1.rev != w2.rev) {
        return w1.rev < w2.rev;
    }
    // 优先级 2:字符串长度升序(代表数值大小)
    if (w1.val.size() != w2.val.size()) {
        return w1.val.size() < w2.val.size();
    }
    // 优先级 3:长度相同时比字典序
    return w1.val < w2.val;
}

int main() {
    // 开启快速 I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    if (!(cin >> n)) return 0;

    vector<W> w(n);
    for (int i = 0; i < n; i++) {
        cin >> w[i].val;
        w[i].rev = d_count(w[i].val); // 预计算逆序对
    }

    // 排序
    sort(w.begin(), w.end(), cmp);

    // 输出
    for (int i = 0; i < n; i++) {
        cout << w[i].val << "\n";
    }

    return 0;
}

❌ 易错点总结

  • 漏掉"字符串长度"比较 :直接使用 w1.val < w2.val 会导致 "10" 排在 "9" 前面(字典序错误)。
  • 逆序对变量类型溢出 :当字符串长度达 1000 时,最大逆序对数可能达到 ≈ 5 × 10 5 \approx 5 \times 10^5 ≈5×105,累计总数虽不会溢出 int,但建议统一写成 long long 保证健壮性。

⏱️ 复杂度分析

  • 时间复杂度 : O ( n ⋅ L 2 + n log ⁡ n ⋅ L ) \mathcal{O}(n \cdot L^2 + n \log n \cdot L) O(n⋅L2+nlogn⋅L)
    • 预处理 :计算 n n n 个长度为 L L L 的字符串逆序对,耗时 O ( n ⋅ L 2 ) \mathcal{O}(n \cdot L^2) O(n⋅L2)。
    • 排序瓶颈 :排序比较共进行 O ( n log ⁡ n ) \mathcal{O}(n \log n) O(nlogn) 次,每次比较耗时 O ( L ) \mathcal{O}(L) O(L)。
    • 实际测试数据中,总运行时间控制在 20ms~160ms 之间,轻松 AC。
  • 空间复杂度 : O ( n ⋅ L ) \mathcal{O}(n \cdot L) O(n⋅L),用于存储 n n n 个长为 L L L 的字符串结构体数组。
相关推荐
zh_xuan17 分钟前
LeeCode 496. 下一个更大元素I
数据结构·算法·栈·单调栈
机 _ 长26 分钟前
05 智算运维|8 张卡怎么才算「捆成一张」:NCCL 实测与拓扑
运维·人工智能·算法·智算运维
早起CaiCai1 小时前
【2023-01 OM】利用深度学习算法融合异质观测实现海洋场降尺度
人工智能·深度学习·算法
梦里寻码2 小时前
我用 NestJS + Vue3 写了一套完整的研发管理系统(58 表 / 229 API / 130 项断言,全开源
前端·后端·算法
猿人谷2 小时前
Surrogate Model:让进化算法学会“预测”,为什么它正在成为智能优化的重要技术?
后端·算法·架构
青少儿编程课堂4 小时前
蓝桥杯青少组图形化 STEMA 省考(报名倒计时·11/22开考)+ 全国青少年信息素养大赛 2026—2027赛季 + 电子学会图形化考级:校园华容道大闯关
c++·python·算法·bfs·信息学竞赛
在猴站学算法5 小时前
(《统计学习方法》(第2版) 李航)第2章 感知机算法
学习·算法·机器学习·统计学习
Rainmicro5 小时前
【无标题】
java·数据库·算法
NEFU_Jyj15 小时前
牛客周赛R168
算法