【算法刷题】蓝桥杯: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 的字符串结构体数组。
相关推荐
linux-hzh1 小时前
百日算法修炼 · Day 12
算法·深度优先
额额额对了2 小时前
数据结构:二叉树
c语言·数据结构·算法
iNeuOS工业互联网2 小时前
iNeuOS_Vision_视觉分析,增加SAM3模型对实例分割和目标检测AI自动标注图片样本功能
人工智能·算法·目标检测
qeen872 小时前
【数据结构】红黑树的算法原理解析与实现
开发语言·数据结构·c++·算法·红黑树
码匠许师傅2 小时前
【C++ 面试真题】20. 聊聊 C++ 的标准库常用算法
c++·算法·面试
m0_547486663 小时前
《数据结构与算法(Python语言版)》全套PPT课件2026
数据结构·算法
个 人 练 习 生3 小时前
数据结构入门:算法复杂度
开发语言·数据结构·经验分享·学习·程序人生·算法
Ricardo-Yang3 小时前
无人机单目深度估计测试:ZipDepth 与 AerialMetric
人工智能·算法·机器学习·计算机视觉·无人机
Nil2084 小时前
golang解决单词转换
算法